diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..d697d17 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,31 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + push: + branches: [ "2.15.1-prerelease" ] + pull_request: + branches: [ "2.15.1-prerelease" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn -B package --file pom.xml diff --git a/README.md b/README.md index 717e9d0..4203184 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ -[![GitHub Pre-Release](https://img.shields.io/github/release-pre/CozmycDev/JedCore.svg)](https://github.com/CozmycDev/JedCore/releases) -[![Github All Releases](https://img.shields.io/github/downloads/CozmycDev/JedCore/total.svg)](https://github.com/CozmycDev/JedCore/releases) -![Size](https://img.shields.io/github/repo-size/CozmycDev/JedCore.svg) +[![GitHub Pre-Release](https://img.shields.io/github/release-pre/Hihelloy-main/JedCore.svg)](https://github.com/Hihelloy-main/JedCore/releases) +[![Github All Releases](https://img.shields.io/github/downloads/Hihelloy-main/JedCore/total.svg)](https://github.com/Hihelloy-main/JedCore/releases) +![Size](https://img.shields.io/github/repo-size/Hihelloy-main/JedCore.svg) # JedCore -This is my fork of plushmonkey's fork of jedk1's JedCore addon for ProjectKorra. -Download releases [here](https://github.com/CozmycDev/JedCore/releases). +This is my fork of Cozymc's fork of plushmonkey's fork of jedk1's JedCore addon for ProjectKorra. +Download releases [here](https://github.com/Hihelloy-main/JedCore/releases). Join our [Discord](https://discord.gg/gh9MfDmwZm) to discuss the plugin, suggest changes, report bugs, etc. +This fork attempts on adding Folia support. + ## Changelog ### 2.14.4 diff --git a/pom.xml b/pom.xml index 647a300..665826b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.jedk1 jedcore - 2.15.0-PK1.11.1 + 2.15.1-PRE-RELEASE-3-PK1.12.1 jar JedCore @@ -13,22 +13,48 @@ spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + papermc + https://repo.papermc.io/repository/maven-public/ + + + jitpack.io + https://jitpack.io + + - - - org.spigotmc - spigot-api - 1.20.2-R0.1-SNAPSHOT - provided - - - com.projectkorra - projectkorra - 1.11.1 - + + com.projectkorra + projectkorra + 1.12.1-PRE-RELEASE-1 + provided + + + + org.spigotmc + spigot-api + 1.20.2-R0.1-SNAPSHOT + provided + + + + com.google.guava + guava + 33.5.0-jre + + + com.cjcrafter + foliascheduler + 0.7.2 + + + org.jetbrains + annotations + 26.0.2-1 + @@ -51,8 +77,8 @@ maven-compiler-plugin 3.8.0 - 9 - 9 + 17 + 17 @@ -63,6 +89,47 @@ ${dir} + + org.apache.maven.plugins + maven-shade-plugin + 3.4.1 + + + package + shade + + + + com.google.guava + com.jedk1.jedcore.libs.googleguava + + + org.jetbrains.annotations + com.jedk1.jedcore.libs.jetbrains + + + com.cjcrafter.foliascheduler + com.jedk1.jedcore.libs.foliascheduler + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + META-INF/versions/** + META-INF/*.kotlin_module + + + + false + + + + diff --git a/src/com/jedk1/jedcore/JCManager.java b/src/com/jedk1/jedcore/JCManager.java index 5fda987..2dfa835 100644 --- a/src/com/jedk1/jedcore/JCManager.java +++ b/src/com/jedk1/jedcore/JCManager.java @@ -1,27 +1,29 @@ package com.jedk1.jedcore; +import com.jedk1.jedcore.ability.earthbending.EarthPillar; +import com.jedk1.jedcore.ability.firebending.LightningBurst; +import com.jedk1.jedcore.ability.waterbending.HealingWaters; +import com.jedk1.jedcore.ability.waterbending.IcePassive; +import com.jedk1.jedcore.ability.waterbending.IceWall; +import com.jedk1.jedcore.util.RegenTempBlock; import org.bukkit.Bukkit; - import com.jedk1.jedcore.ability.firebending.LightningBurst; - import com.jedk1.jedcore.ability.waterbending.HealingWaters; - import com.jedk1.jedcore.ability.waterbending.IcePassive; - import com.jedk1.jedcore.util.RegenTempBlock; - public class JCManager implements Runnable { - public JedCore plugin; - - public JCManager(JedCore plugin) { - this.plugin = plugin; - } - - public void run() { - LightningBurst.progressAll(); - - HealingWaters.heal(Bukkit.getServer()); - IcePassive.handleSkating(); -// IceWall.progressAll(); - - RegenTempBlock.manage(); - } + public JedCore plugin; + + public JCManager(JedCore plugin) { + this.plugin = plugin; + } + + public void run() { + LightningBurst.progressAll(); + + HealingWaters.heal(Bukkit.getServer()); + //IcePassive.handleSkating(); + IceWall.progressAll(); + EarthPillar.progressAll(); + + RegenTempBlock.manage(); + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/JCMethods.java b/src/com/jedk1/jedcore/JCMethods.java index 27d4ddb..abc4d74 100644 --- a/src/com/jedk1/jedcore/JCMethods.java +++ b/src/com/jedk1/jedcore/JCMethods.java @@ -1,356 +1,358 @@ package com.jedk1.jedcore; -import java.util.*; - -import com.jedk1.jedcore.util.*; +import com.jedk1.jedcore.command.Commands; +import com.jedk1.jedcore.configuration.JedCoreConfig; +import com.jedk1.jedcore.util.FireTick; +import com.jedk1.jedcore.util.LightManagerUtil; +import com.jedk1.jedcore.util.RegenTempBlock; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ProjectKorra; +import com.projectkorra.projectkorra.ability.CoreAbility; import com.projectkorra.projectkorra.ability.ElementalAbility; +import com.projectkorra.projectkorra.ability.WaterAbility; +import com.projectkorra.projectkorra.ability.util.ComboManager; import com.projectkorra.projectkorra.region.RegionProtection; -import org.bukkit.*; +import com.projectkorra.projectkorra.util.TempBlock; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.Levelled; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; -import com.jedk1.jedcore.configuration.JedCoreConfig; -import com.jedk1.jedcore.scoreboard.BendingBoard; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ProjectKorra; -import com.projectkorra.projectkorra.ability.CoreAbility; -import com.projectkorra.projectkorra.ability.util.ComboManager; -import com.projectkorra.projectkorra.util.TempBlock; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; public class JCMethods { - private static final ArrayList SMALL_PLANTS = new ArrayList(){{ - addAll(Arrays.asList(Material.GRASS_BLOCK, Material.FERN, Material.POPPY, Material.DANDELION, Material.OAK_SAPLING, - Material.SPRUCE_SAPLING, Material.BIRCH_SAPLING, Material.JUNGLE_SAPLING, Material.ACACIA_SAPLING, - Material.DARK_OAK_SAPLING, Material.ALLIUM, Material.ORANGE_TULIP, Material.PINK_TULIP, Material.RED_TULIP, - Material.WHITE_TULIP, Material.ROSE_BUSH, Material.BLUE_ORCHID, Material.LILAC, Material.OXEYE_DAISY, - Material.AZURE_BLUET, Material.PEONY, Material.SUNFLOWER, Material.LARGE_FERN, Material.RED_MUSHROOM, - Material.BROWN_MUSHROOM, Material.PUMPKIN_STEM, Material.MELON_STEM, Material.WHEAT, Material.TALL_GRASS, - Material.BEETROOTS, Material.CARROTS, Material.POTATOES, Material.CRIMSON_FUNGUS, Material.WARPED_FUNGUS, - Material.BAMBOO, Material.BAMBOO_SAPLING)); - int serverVersion = GeneralMethods.getMCVersion(); - if (serverVersion >= 1170) { - add(Material.getMaterial("AZALEA")); - add(Material.getMaterial("FLOWERING_AZALEA")); - add(Material.getMaterial("FLOWERING_AZALEA_LEAVES")); - add(Material.getMaterial("AZALEA_LEAVES")); - add(Material.getMaterial("BIG_DRIPLEAF")); - add(Material.getMaterial("BIG_DRIPLEAF_STEM")); - add(Material.getMaterial("SMALL_DRIPLEAF")); - add(Material.getMaterial("HANGING_ROOTS")); - add(Material.getMaterial("GLOW_LICHEN")); - add(Material.getMaterial("CAVE_VINES")); - add(Material.getMaterial("CAVE_VINES_PLANT")); - } - }}; - - private static List worlds = new ArrayList<>(); - private static List combos = new ArrayList<>(); - - public static List getDisabledWorlds() { - return JCMethods.worlds; - } - - public static void registerDisabledWorlds() { - worlds.clear(); - List registeredworlds = ProjectKorra.plugin.getConfig().getStringList("Properties.DisabledWorlds"); - if (!registeredworlds.isEmpty()) { - worlds.addAll(registeredworlds); - } - } - - public static boolean isDisabledWorld(World world) { - return getDisabledWorlds().contains(world.getName()); - } - - public static List getCombos() { - return JCMethods.combos; - } - - public static void registerCombos() { - combos.clear(); - combos.addAll(ComboManager.getComboAbilities().keySet()); - } - - /** - * Gets the points of a line between two points. - * @param startLoc - * @param endLoc - * @param points - * @return locations - */ - public static List getLinePoints(Location startLoc, Location endLoc, int points){ - List locations = new ArrayList(); - Location diff = endLoc.subtract(startLoc); - double diffX = diff.getX() / points; - double diffY = diff.getY() / points; - double diffZ = diff.getZ() / points; - Location loc = startLoc; - for(int i = 0; i < points; i++){ - loc.add(new Location(startLoc.getWorld(), diffX, diffY, diffZ)); - locations.add(loc.clone()); - } - return locations; - } - - public static List getCirclePoints(Location location, int points, double size) { - return getCirclePoints(location, points, size, 0); - } - - /** - * Gets points in a circle. - * @param location - * @param points - * @param size - * @return - */ - public static List getCirclePoints(Location location, int points, double size, double startangle){ - List locations = new ArrayList(); - for(int i = 0; i < 360; i += 360/points){ - double angle = (i * Math.PI / 180); - double x = size * Math.cos(angle + startangle); - double z = size * Math.sin(angle + startangle); - Location loc = location.clone(); - loc.add(x, 0, z); - locations.add(loc); - } - return locations; - } - - /** - * Gets points in a vertical circle. - * @param location - * @param points - * @param size - * @param yawOffset - * @return - */ - public static List getVerticalCirclePoints(Location location, int points, double size, float yawOffset) { - List locations = new ArrayList<>(); - Location fakeLoc = location.clone(); - fakeLoc.setPitch(0); - fakeLoc.setYaw(yawOffset); - Vector direction = fakeLoc.getDirection(); - - for(double j = -180; j <= 180; j += points){ - Location tempLoc = fakeLoc.clone(); - Vector newDir = direction.clone().multiply(size * Math.cos(Math.toRadians(j))); - tempLoc.add(newDir); - tempLoc.setY(tempLoc.getY() + size + (size * Math.sin(Math.toRadians(j)))); - locations.add(tempLoc.clone()); - } - return locations; - } - - /** - * Remove an item from a players inventory. - * @param player - * @param material - * @param amount - * @return - */ - public static boolean removeItemFromInventory(Player player, Material material, int amount) { - for (ItemStack item : player.getInventory().getContents()) { - if (item != null && item.getType() == material) { - if (item.getAmount() == amount) { - Map remaining = player.getInventory().removeItem(item); - - if (!remaining.isEmpty()) { - ItemStack offhand = player.getInventory().getItemInOffHand(); - - // Spigot seems to not handle offhand correctly with removeItem, so try to manually remove it. - if (offhand != null && offhand.getType() == material && offhand.getAmount() == amount) { - player.getInventory().setItemInOffHand(null); - } - } - } else if (item.getAmount() > amount) { - item.setAmount(item.getAmount() - amount); - } - - return true; - } - } - - return false; - } - - /** - * Gets points in a spiral shape. - * @param location - * @param points - * @param spiralCount - * @param startAngle - * @param startSize - * @param finalSize - * @param noClip - * @return - */ - public static List getSpiralPoints(Location location, int points, int spiralCount, int startAngle, double startSize, double finalSize, boolean noClip){ - return getSpiralPoints(location, points, spiralCount, 0.0D, startAngle, startSize, finalSize, noClip); - } - - /** - * Gets points in a vertical spiral shape, could be used for a tornado. - * @param location - * @param points - * @param spiralCount - * @param height - * @param startAngle - * @param startSize - * @param finalSize - * @param noClip - * @return - */ - public static List getSpiralPoints(Location location, int points, int spiralCount, double height, int startAngle, double startSize, double finalSize, boolean noClip){ - List locations = new ArrayList(); - - points = points/spiralCount; - double sizeIncr = ((finalSize - startSize) / points)/spiralCount; - double hightIncr = (height/points)/spiralCount; - double size = startSize; - for(int i = 0; i < spiralCount; i++){ - for(int j = 0; j < 360; j += 360/points){ - hightIncr = hightIncr + ((height/points)/spiralCount); - size = size + sizeIncr; - double angle = (j * Math.PI / 180); - double x = size * Math.cos(angle + startAngle); - double z = size * Math.sin(angle + startAngle); - Location loc = location.clone(); - loc.add(x, hightIncr, z); - if(!noClip && ElementalAbility.isAir(loc.getBlock().getType())) - locations.add(loc); - else if(noClip) - locations.add(loc); - } - } - - return locations; - } - - public static void extinguishBlocks(Player player, String ability, int range, int radius, boolean fire, boolean lava){ - for (Block block : GeneralMethods.getBlocksAroundPoint(player.getTargetBlock(null, range).getLocation(), radius)) { - Material mat = block.getType(); - if(mat != Material.FIRE && mat != Material.LAVA && mat != Material.SOUL_FIRE) - continue; - if (RegionProtection.isRegionProtected(player, block.getLocation(), ability)) - continue; - if (((mat == Material.FIRE || mat == Material.SOUL_FIRE) && fire)||(mat == Material.LAVA && lava)) { - block.setType(mat != Material.LAVA ? Material.AIR : isLiquidSource(block) ? Material.OBSIDIAN : Material.COBBLESTONE); - block.getWorld().playEffect(block.getLocation(), Effect.EXTINGUISH, 0); - } - } - } - - /** - * Checks if 3 blocks around the block are of the required type. - * @param block - * @param type - * @return - */ - public static boolean isAdjacentToThreeOrMoreSources(Block block, Material type) { - if (TempBlock.isTempBlock(block)) { - return false; - } - int sources = 0; - BlockFace[] faces = { BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN }; - for (BlockFace face : faces) { - Block blocki = block.getRelative(face); - if ((blocki.getType() == type)) { - sources++; - } - } - if (sources >= 2) - return true; - return false; - } - - static Material[] unbreakables = { Material.BEDROCK, Material.BARRIER, - Material.NETHER_PORTAL, Material.END_PORTAL, - Material.END_PORTAL_FRAME, Material.OBSIDIAN}; - - public static boolean isUnbreakable(Block block) { - if (block.getState() instanceof InventoryHolder) { - return true; - } - if (Arrays.asList(unbreakables).contains(block.getType())) - return true; - return false; - } - - public static boolean isLiquidSource(Block block) { - if (!block.isLiquid()) { - return false; - } - - if (!(block.getBlockData() instanceof Levelled)) { - return false; - } - - Levelled levelData = (Levelled) block.getBlockData(); - - return levelData.getLevel() == 0; - } - - // TODO: Should this be reimplemented or has the rpg plugin been abandoned? - public static boolean isSozinsComet(World world) { - return false; - } - - // TODO: Should this be reimplemented or has the rpg plugin been abandoned? - public static boolean isLunarEclipse(World world) { - return false; - } - - public static boolean isDoublePlant(Material material) { - return material == Material.SUNFLOWER || material == Material.LILAC || material == Material.TALL_GRASS || - material == Material.LARGE_FERN || material == Material.ROSE_BUSH || material == Material.PEONY; - } - - public static boolean isSmallPlant(Block block) { - return isSmallPlant(block.getType()); - } - - public static boolean isSmallPlant(Material material) { - return SMALL_PLANTS.contains(material); - } - - public static void displayColoredParticles(String hex, Location location, int amount, double offsetX, double offsetY, double offsetZ, double extra) { - displayColoredParticles(hex, location, amount, offsetX, offsetY, offsetZ, extra, 255); - } - - public static void displayColoredParticles(String hex, Location location, int amount, double offsetX, double offsetY, double offsetZ, double extra, int alpha) { - JedCore.plugin.getParticleAdapter().displayColoredParticles(hex, location, amount, offsetX, offsetY, offsetZ, extra, alpha); - } - - public static void emitLight(Location loc) { - ConfigurationSection config = JedCoreConfig.getConfig((Player)null); - if (config.getBoolean("Properties.Fire.DynamicLight.Enabled")) { - int brightness = config.getInt("Properties.Fire.DynamicLight.Brightness"); - long keepAlive = config.getLong("Properties.Fire.DynamicLight.KeepAlive"); - - LightManager.createLight(loc).brightness(brightness).timeUntilFadeout(keepAlive).emit(); - } - } - - public static void reload() { - JedCore.log.info("JedCore Reloaded."); - JedCore.plugin.reloadConfig(); - JedCore.logDebug = JedCoreConfig.getConfig((World)null).getBoolean("Properties.LogDebug"); - JedCoreConfig.board.reloadConfig(); - CoreAbility.registerPluginAbilities(JedCore.plugin, "com.jedk1.jedcore.ability"); - registerDisabledWorlds(); - registerCombos(); - RegenTempBlock.revertAll(); - BendingBoard.setFields(); - BendingBoard.updateOnline(); - JedCore.plugin.initializeCollisions(); - FireTick.loadMethod(); - - BendingBoard.loadOtherCooldowns(); - } -} + + // todo: either use PKs isPlant or the registry/tags (with config) + private static final ArrayList SMALL_PLANTS = new ArrayList(){{ + addAll(Arrays.asList(Material.GRASS, Material.FERN, Material.POPPY, Material.DANDELION, Material.OAK_SAPLING, + Material.SPRUCE_SAPLING, Material.BIRCH_SAPLING, Material.JUNGLE_SAPLING, Material.ACACIA_SAPLING, + Material.DARK_OAK_SAPLING, Material.ALLIUM, Material.ORANGE_TULIP, Material.PINK_TULIP, Material.RED_TULIP, + Material.WHITE_TULIP, Material.ROSE_BUSH, Material.BLUE_ORCHID, Material.LILAC, Material.OXEYE_DAISY, + Material.AZURE_BLUET, Material.PEONY, Material.SUNFLOWER, Material.LARGE_FERN, Material.RED_MUSHROOM, + Material.BROWN_MUSHROOM, Material.PUMPKIN_STEM, Material.MELON_STEM, Material.WHEAT, Material.TALL_GRASS, + Material.BEETROOTS, Material.CARROTS, Material.POTATOES, Material.CRIMSON_FUNGUS, Material.WARPED_FUNGUS, + Material.BAMBOO, Material.BAMBOO_SAPLING)); + + int serverVersion = GeneralMethods.getMCVersion(); + if (serverVersion >= 1170) { + add(Material.getMaterial("AZALEA")); + add(Material.getMaterial("FLOWERING_AZALEA")); + add(Material.getMaterial("FLOWERING_AZALEA_LEAVES")); + add(Material.getMaterial("AZALEA_LEAVES")); + add(Material.getMaterial("BIG_DRIPLEAF")); + add(Material.getMaterial("BIG_DRIPLEAF_STEM")); + add(Material.getMaterial("SMALL_DRIPLEAF")); + add(Material.getMaterial("HANGING_ROOTS")); + add(Material.getMaterial("GLOW_LICHEN")); + add(Material.getMaterial("CAVE_VINES")); + add(Material.getMaterial("CAVE_VINES_PLANT")); + } + }}; + + private static List worlds = new ArrayList<>(); + private static List combos = new ArrayList<>(); + + public static List getDisabledWorlds() { + return JCMethods.worlds; + } + + public static void registerDisabledWorlds() { + worlds.clear(); + List registeredworlds = ProjectKorra.plugin.getConfig().getStringList("Properties.DisabledWorlds"); + if (!registeredworlds.isEmpty()) { + worlds.addAll(registeredworlds); + } + } + + public static boolean isDisabledWorld(World world) { + return getDisabledWorlds().contains(world.getName()); + } + + public static List getCombos() { + return JCMethods.combos; + } + + public static void registerCombos() { + combos.clear(); + combos.addAll(ComboManager.getComboAbilities().keySet()); + } + + /** + * Gets the points of a line between two points. + * @param startLoc + * @param endLoc + * @param points + * @return locations + */ + public static List getLinePoints(Location startLoc, Location endLoc, int points){ + List locations = new ArrayList(); + Location diff = endLoc.subtract(startLoc); + double diffX = diff.getX() / points; + double diffY = diff.getY() / points; + double diffZ = diff.getZ() / points; + Location loc = startLoc; + for(int i = 0; i < points; i++){ + loc.add(new Location(startLoc.getWorld(), diffX, diffY, diffZ)); + locations.add(loc.clone()); + } + return locations; + } + + public static List getCirclePoints(Location location, int points, double size) { + return getCirclePoints(location, points, size, 0); + } + + /** + * Gets points in a circle. + * @param location + * @param points + * @param size + * @return + */ + public static List getCirclePoints(Location location, int points, double size, double startangle){ + List locations = new ArrayList(); + for(int i = 0; i < 360; i += 360/points){ + double angle = (i * Math.PI / 180); + double x = size * Math.cos(angle + startangle); + double z = size * Math.sin(angle + startangle); + Location loc = location.clone(); + loc.add(x, 0, z); + locations.add(loc); + } + return locations; + } + + /** + * Gets points in a vertical circle. + * @param location + * @param points + * @param size + * @param yawOffset + * @return + */ + public static List getVerticalCirclePoints(Location location, int points, double size, float yawOffset) { + List locations = new ArrayList<>(); + Location fakeLoc = location.clone(); + fakeLoc.setPitch(0); + fakeLoc.setYaw(yawOffset); + Vector direction = fakeLoc.getDirection(); + + for(double j = -180; j <= 180; j += points){ + Location tempLoc = fakeLoc.clone(); + Vector newDir = direction.clone().multiply(size * Math.cos(Math.toRadians(j))); + tempLoc.add(newDir); + tempLoc.setY(tempLoc.getY() + size + (size * Math.sin(Math.toRadians(j)))); + locations.add(tempLoc.clone()); + } + return locations; + } + + /** + * Remove an item from a players inventory. + * @param player + * @param material + * @param amount + * @return + */ + public static boolean removeItemFromInventory(Player player, Material material, int amount) { + for (ItemStack item : player.getInventory().getContents()) { + if (item != null && item.getType() == material) { + if (item.getAmount() == amount) { + Map remaining = player.getInventory().removeItem(item); + + if (!remaining.isEmpty()) { + ItemStack offhand = player.getInventory().getItemInOffHand(); + + // Spigot seems to not handle offhand correctly with removeItem, so try to manually remove it. + if (offhand != null && offhand.getType() == material && offhand.getAmount() == amount) { + player.getInventory().setItemInOffHand(null); + } + } + } else if (item.getAmount() > amount) { + item.setAmount(item.getAmount() - amount); + } + + return true; + } + } + + return false; + } + + /** + * Gets points in a spiral shape. + * @param location + * @param points + * @param spiralCount + * @param startAngle + * @param startSize + * @param finalSize + * @param noClip + * @return + */ + public static List getSpiralPoints(Location location, int points, int spiralCount, int startAngle, double startSize, double finalSize, boolean noClip){ + return getSpiralPoints(location, points, spiralCount, 0.0D, startAngle, startSize, finalSize, noClip); + } + + /** + * Gets points in a vertical spiral shape, could be used for a tornado. + * @param location + * @param points + * @param spiralCount + * @param height + * @param startAngle + * @param startSize + * @param finalSize + * @param noClip + * @return + */ + public static List getSpiralPoints(Location location, int points, int spiralCount, double height, int startAngle, double startSize, double finalSize, boolean noClip){ + List locations = new ArrayList(); + + points = points/spiralCount; + double sizeIncr = ((finalSize - startSize) / points)/spiralCount; + double hightIncr = (height/points)/spiralCount; + double size = startSize; + for(int i = 0; i < spiralCount; i++){ + for(int j = 0; j < 360; j += 360/points){ + hightIncr = hightIncr + ((height/points)/spiralCount); + size = size + sizeIncr; + double angle = (j * Math.PI / 180); + double x = size * Math.cos(angle + startAngle); + double z = size * Math.sin(angle + startAngle); + Location loc = location.clone(); + loc.add(x, hightIncr, z); + if(!noClip && ElementalAbility.isAir(loc.getBlock().getType())) + locations.add(loc); + else if(noClip) + locations.add(loc); + } + } + + return locations; + } + + public static void extinguishBlocks(Player player, String ability, int range, int radius, boolean fire, boolean lava){ + for (Block block : GeneralMethods.getBlocksAroundPoint(player.getTargetBlock(null, range).getLocation(), radius)) { + Material mat = block.getType(); + if(mat != Material.FIRE && mat != Material.LAVA && mat != Material.SOUL_FIRE) + continue; + if (RegionProtection.isRegionProtected(player, block.getLocation(), ability)) + continue; + if (((mat == Material.FIRE || mat == Material.SOUL_FIRE) && fire)||(mat == Material.LAVA && lava)) { + block.setType(mat != Material.LAVA ? Material.AIR : isLiquidSource(block) ? Material.OBSIDIAN : Material.COBBLESTONE); + block.getWorld().playEffect(block.getLocation(), Effect.EXTINGUISH, 0); + } + } + } + + /** + * Checks if 3 blocks around the block are of the required type. + * @param block + * @param type + * @return + */ + public static boolean isAdjacentToThreeOrMoreSources(Block block, Material type) { + if (TempBlock.isTempBlock(block)) { + return false; + } + int sources = 0; + BlockFace[] faces = { BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN }; + for (BlockFace face : faces) { + Block blocki = block.getRelative(face); + if ((blocki.getType() == type)) { + sources++; + } + } + if (sources >= 2) + return true; + return false; + } + + static Material[] unbreakables = { Material.BEDROCK, Material.BARRIER, + Material.NETHER_PORTAL, Material.END_PORTAL, + Material.END_PORTAL_FRAME, Material.OBSIDIAN}; + + public static boolean isUnbreakable(Block block) { + if (block.getState() instanceof InventoryHolder) { + return true; + } + if (Arrays.asList(unbreakables).contains(block.getType())) + return true; + return false; + } + + public static boolean isLiquidSource(Block block) { + if (!block.isLiquid()) { + return false; + } + + if (!(block.getBlockData() instanceof Levelled)) { + return false; + } + + Levelled levelData = (Levelled) block.getBlockData(); + + return levelData.getLevel() == 0; + } + + // TODO: Should this be reimplemented or has the rpg plugin been abandoned? + public static boolean isSozinsComet(World world) { + return false; + } + + // TODO: Should this be reimplemented or has the rpg plugin been abandoned? + public static boolean isLunarEclipse(World world) { + return false; + } + + // todo: see SMALL_PLANTS + public static boolean isDoublePlant(Material material) { + return material == Material.SUNFLOWER || material == Material.LILAC || material == Material.TALL_GRASS || + material == Material.LARGE_FERN || material == Material.ROSE_BUSH || material == Material.PEONY; + } + + public static boolean isSmallPlant(Block block) { + return isSmallPlant(block.getType()); + } + + public static boolean isSmallPlant(Material material) { + return WaterAbility.isPlant(material); + //return SMALL_PLANTS.contains(material); + } + + public static void displayColoredParticles(String hex, Location location, int amount, double offsetX, double offsetY, double offsetZ, double extra) { + displayColoredParticles(hex, location, amount, offsetX, offsetY, offsetZ, extra, 255); + } + + public static void displayColoredParticles(String hex, Location location, int amount, double offsetX, double offsetY, double offsetZ, double extra, int alpha) { + JedCore.plugin.getParticleAdapter().displayColoredParticles(hex, location, amount, offsetX, offsetY, offsetZ, extra, alpha); + } + + public static void emitLight(Location loc) { + LightManagerUtil.emitFirebendingLight(loc); + } + + public static void reload() { + JedCore.log.info("JedCore Reloaded."); + JedCore.plugin.reloadConfig(); + JedCore.logDebug = JedCoreConfig.getConfig((World)null).getBoolean("Properties.LogDebug"); + CoreAbility.registerPluginAbilities(JedCore.plugin, "com.jedk1.jedcore.ability"); + registerDisabledWorlds(); + registerCombos(); + RegenTempBlock.revertAll(); + JedCore.plugin.initializeCollisions(); + FireTick.loadMethod(); + new Commands(); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/JedCore.java b/src/com/jedk1/jedcore/JedCore.java index b29466e..2ae6116 100644 --- a/src/com/jedk1/jedcore/JedCore.java +++ b/src/com/jedk1/jedcore/JedCore.java @@ -1,25 +1,27 @@ package com.jedk1.jedcore; -import java.io.IOException; -import java.util.logging.*; +import com.cjcrafter.foliascheduler.FoliaCompatibility; +import com.cjcrafter.foliascheduler.ServerImplementation; import com.google.common.reflect.ClassPath; import com.jedk1.jedcore.util.*; +import com.jedk1.jedcore.command.Commands; +import com.jedk1.jedcore.configuration.JedCoreConfig; +import com.jedk1.jedcore.listener.AbilityListener; +import com.jedk1.jedcore.listener.CommandListener; +import com.jedk1.jedcore.listener.JCListener; +import com.jedk1.jedcore.util.ChiRestrictor; import com.jedk1.jedcore.util.versionadapter.ParticleAdapter; import com.jedk1.jedcore.util.versionadapter.ParticleAdapterFactory; import com.jedk1.jedcore.util.versionadapter.PotionEffectAdapter; import com.jedk1.jedcore.util.versionadapter.PotionEffectAdapterFactory; +import com.projectkorra.projectkorra.ability.CoreAbility; +import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.plugin.java.JavaPlugin; -import com.jedk1.jedcore.command.Commands; -import com.jedk1.jedcore.configuration.JedCoreConfig; -import com.jedk1.jedcore.listener.AbilityListener; -import com.jedk1.jedcore.listener.CommandListener; -import com.jedk1.jedcore.listener.JCListener; -import com.jedk1.jedcore.scoreboard.BendingBoard; -import com.projectkorra.projectkorra.ability.CoreAbility; -import org.bukkit.scheduler.BukkitRunnable; +import java.io.IOException; +import java.util.logging.Logger; public class JedCore extends JavaPlugin { @@ -28,61 +30,100 @@ public class JedCore extends JavaPlugin { public static String dev; public static String version; public static boolean logDebug; + public static boolean isFolia; + public static boolean luminol; + public static boolean paper; + public static boolean spigot; + public static ServerImplementation scheduler; - private ParticleAdapter particleAdapter; + private ParticleAdapter particleAdapter; private PotionEffectAdapter potionEffectAdapter; @Override public void onEnable() { + scheduler = new FoliaCompatibility(this).getServerImplementation(); plugin = this; - JedCore.log = this.getLogger(); + log = this.getLogger(); new JedCoreConfig(this); - logDebug = JedCoreConfig.getConfig((World)null).getBoolean("Properties.LogDebug"); - + logDebug = JedCoreConfig.getConfig((World) null).getBoolean("Properties.LogDebug"); + dev = this.getDescription().getAuthors().toString().replace("[", "").replace("]", ""); version = this.getDescription().getVersion(); + try { + Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); + isFolia = true; + } catch (ClassNotFoundException ignored) {} + + try { + Class.forName("com.destroystokyo.paper.PaperConfig"); + paper = true; + } catch (ClassNotFoundException ignored) {} + + try { + Class.forName("me.earthme.luminol.api.ThreadedRegion"); + luminol = true; + } catch (ClassNotFoundException ignored) {} + + + if (paper && !luminol) { + getLogger().info("Server is running on Paper/Folia"); + } + + if (luminol) { + getLogger().info("Server is running on Luminol"); + } + + if (!luminol && !isFolia && !paper) { + spigot = true; + getLogger().info("Server is running on Spigot"); + } + JCMethods.registerDisabledWorlds(); - CoreAbility.registerPluginAbilities(plugin, "com.jedk1.jedcore.ability"); + CoreAbility.registerPluginAbilities(this, "com.jedk1.jedcore.ability"); + getServer().getPluginManager().registerEvents(new AbilityListener(this), this); getServer().getPluginManager().registerEvents(new CommandListener(this), this); getServer().getPluginManager().registerEvents(new JCListener(this), this); getServer().getPluginManager().registerEvents(new ChiRestrictor(), this); - getServer().getScheduler().scheduleSyncRepeatingTask(this, new JCManager(this), 0, 1); - - BendingBoard.updateOnline(); - new Commands(); + // Repeating logic task - uses ThreadUtil + ThreadUtil.runGlobalTimer(new JCManager(this), 0L, 1L); + ThreadUtil.runGlobalTimer(RegenTempBlock::manage, 0L, 1L); + + new Commands(); FireTick.loadMethod(); - ParticleAdapterFactory particleAdapterFactory = new ParticleAdapterFactory(); - particleAdapter = particleAdapterFactory.getAdapter(); + particleAdapter = new ParticleAdapterFactory().getAdapter(); + potionEffectAdapter = new PotionEffectAdapterFactory().getAdapter(); - PotionEffectAdapterFactory potionEffectAdapterFactory = new PotionEffectAdapterFactory(); - potionEffectAdapter = potionEffectAdapterFactory.getAdapter(); + checkMaintainer(); - new BukkitRunnable() { - @Override - public void run() { - JCMethods.registerCombos(); - BendingBoard.loadOtherCooldowns(); - initializeCollisions(); - } - }.runTaskLater(this, 1); - - try { - MetricsLite metrics = new MetricsLite(this); - metrics.start(); - log.info("Initialized Metrics."); - } catch (IOException e) { - log.info("Failed to submit statistics for MetricsLite."); - } + // Delayed combo/collision init + ThreadUtil.runGlobalLater(() -> { + JCMethods.registerCombos(); + initializeCollisions(); + }, 1L); + + + try { + MetricsLite metrics = new MetricsLite(this); + metrics.start(); + log.info("Initialized Metrics."); + } catch (IOException e) { + log.info("Failed to submit statistics for MetricsLite."); + } } - public void initializeCollisions() { - boolean enabled = this.getConfig().getBoolean("Properties.AbilityCollisions.Enabled"); + public static void checkMaintainer() { + if (!dev.contains("Cozmyc (Maintainer), Hihelloy (Updater)")) { + dev = dev + ", Cozmyc (Maintainer), Hihelloy (Updater)"; + } + } + public void initializeCollisions() { + boolean enabled = getConfig().getBoolean("Properties.AbilityCollisions.Enabled"); if (!enabled) { getLogger().info("Collisions disabled."); return; @@ -94,21 +135,19 @@ public void initializeCollisions() { for (ClassPath.ClassInfo info : cp.getTopLevelClassesRecursive("com.jedk1.jedcore.ability")) { try { @SuppressWarnings("unchecked") - Class abilityClass = (Class)Class.forName(info.getName()); - + Class abilityClass = (Class) Class.forName(info.getName()); if (abilityClass == null) continue; CollisionInitializer initializer = new CollisionInitializer<>(abilityClass); initializer.initialize(); - } catch (Exception e) { - - } + } catch (Exception ignored) {} } } catch (IOException e) { e.printStackTrace(); } } - + + @Override public void onDisable() { RegenTempBlock.revertAll(); } @@ -120,10 +159,30 @@ public static void logDebug(String message) { } public ParticleAdapter getParticleAdapter() { - return this.particleAdapter; + return particleAdapter; } public PotionEffectAdapter getPotionEffectAdapter() { - return this.potionEffectAdapter; + return potionEffectAdapter; + } + + /** + * + * Determines if the server is running Folia or not + */ + public static boolean isFolia() { + return isFolia; + } + + public static boolean isPaper() { + return paper; } + + public static boolean isLuminol() { + return luminol; + } + + public static boolean isSpigot() { + return spigot; + } } diff --git a/src/com/jedk1/jedcore/ability/airbending/AirBlade.java b/src/com/jedk1/jedcore/ability/airbending/AirBlade.java index 08b814b..c627a35 100644 --- a/src/com/jedk1/jedcore/ability/airbending/AirBlade.java +++ b/src/com/jedk1/jedcore/ability/airbending/AirBlade.java @@ -9,257 +9,322 @@ import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; - -import org.bukkit.Location; +import com.projectkorra.projectkorra.util.TempBlock; +import org.bukkit.*; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class AirBlade extends AirAbility implements AddonAbility { - private Location location; - private Vector direction; - private double travelled; - - @Attribute("Growth") - private double growth = 1; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.RANGE) - private double range; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute("CollisionRadius") - private double entityCollisionRadius; - - public AirBlade(Player player) { - super(player); - if (!bPlayer.canBend(this)) { - return; - } - - setFields(); - - this.location = player.getEyeLocation().clone(); - this.direction = player.getEyeLocation().getDirection().clone(); - - start(); - if (!isRemoved()) - bPlayer.addCooldown(this); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Air.AirBlade.Cooldown"); - range = config.getDouble("Abilities.Air.AirBlade.Range"); - damage = config.getDouble("Abilities.Air.AirBlade.Damage"); - entityCollisionRadius = config.getDouble("Abilities.Air.AirBlade.EntityCollisionRadius"); - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - - if (travelled >= range) { - remove(); - return; - } - - progressBlade(); - } - - private void progressBlade() { - for (int j = 0; j < 2; j++) { - location = location.add(direction.multiply(1)); - playAirbendingSound(location); - travelled++; - growth += 0.125; - if (travelled >= range) { - remove(); - return; - } - - if (!isTransparent(location.getBlock())) { - remove(); - return; - } - - if (RegionProtection.isRegionProtected(player, player.getLocation(), this)) { - remove(); - return; - } - - double pitch = -location.getPitch(); - Location lastLoc = location.clone(); - for (double i = -90 + pitch; i <= 90 + pitch; i += 8) { - Location tempLoc = location.clone(); - tempLoc.setPitch(0); - Vector tempDir = tempLoc.getDirection().clone(); - tempDir.setY(0); - Vector newDir = tempDir.clone().multiply(growth * Math.cos(Math.toRadians(i))); - tempLoc.add(newDir); - tempLoc.setY(tempLoc.getY() + (growth * Math.sin(Math.toRadians(i)))); - playAirbendingParticles(tempLoc, 1, (float) Math.random() / 2, (float) Math.random() / 2, (float) Math.random() / 2); - - if (j == 0) { - // Only check collisions for each block. - if (!lastLoc.getBlock().getLocation().equals(tempLoc.getBlock().getLocation())) { - lastLoc = tempLoc; - - boolean hit = CollisionDetector.checkEntityCollisions(player, new Sphere(tempLoc.toVector(), entityCollisionRadius), (entity) -> { - DamageHandler.damageEntity(entity, damage, this); - remove(); - return true; - }); - - if (hit) { - remove(); - return; - } - } - } - } - } - } - - public Player getPlayer() { - return player; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public List getLocations() { - List locations = new ArrayList<>(); - - double pitch = -location.getPitch(); - for (double i = -90 + pitch; i <= 90 + pitch; i += 8) { - Location tempLoc = location.clone(); - tempLoc.setPitch(0); - Vector tempDir = tempLoc.getDirection().clone(); - tempDir.setY(0); - Vector newDir = tempDir.clone().multiply(growth * Math.cos(Math.toRadians(i))); - tempLoc.add(newDir); - tempLoc.setY(tempLoc.getY() + (growth * Math.sin(Math.toRadians(i)))); - - locations.add(tempLoc); - } - - return locations; - } - - @Override - public double getCollisionRadius() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getDouble("Abilities.Air.AirBlade.AbilityCollisionRadius"); - } - - public long getCooldown() { - return cooldown; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - @Override - public String getName() { - return "AirBlade"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return false; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Air.AirBlade.Description"); - } - - public Vector getDirection() { - return direction; - } - - public void setDirection(Vector direction) { - this.direction = direction; - } - - public double getTravelled() { - return travelled; - } - - public void setTravelled(double travelled) { - this.travelled = travelled; - } - - public double getGrowth() { - return growth; - } - - public void setGrowth(double growth) { - this.growth = growth; - } - - public double getRange() { - return range; - } - - public void setRange(double range) { - this.range = range; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public double getEntityCollisionRadius() { - return entityCollisionRadius; - } - - public void setEntityCollisionRadius(double entityCollisionRadius) { - this.entityCollisionRadius = entityCollisionRadius; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Air.AirBlade.Enabled"); - } -} + private Set cuttableBlocks; + + private Location location; + private Vector direction; + private double travelled; + private boolean blockCuttingEnabled; + private boolean revertCutBlocks; + private long revertTime; + + @Attribute("Growth") + private double growth = 1; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.RANGE) + private double range; + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute("CollisionRadius") + private double entityCollisionRadius; + @Attribute(Attribute.SPEED) + private double speed; + @Attribute(Attribute.KNOCKBACK) + private double knockback; + + public AirBlade(Player player) { + super(player); + if (!bPlayer.canBend(this)) { + return; + } + + setFields(); + + this.location = player.getEyeLocation().clone(); + this.direction = player.getEyeLocation().getDirection().clone(); + + start(); + if (!isRemoved()) + bPlayer.addCooldown(this); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Air.AirBlade.Cooldown"); + range = config.getDouble("Abilities.Air.AirBlade.Range"); + damage = config.getDouble("Abilities.Air.AirBlade.Damage"); + entityCollisionRadius = config.getDouble("Abilities.Air.AirBlade.EntityCollisionRadius"); + speed = config.getDouble("Abilities.Air.AirBlade.Speed"); + knockback = config.getDouble("Abilities.Air.AirBlade.Knockback"); + + @NotNull ConfigurationSection cuttingConfig = Objects.requireNonNull(config.getConfigurationSection("Abilities.Air.AirBlade.BlockCutting")); + + assert cuttingConfig != null; + blockCuttingEnabled = cuttingConfig.getBoolean("Enabled"); + revertCutBlocks = cuttingConfig.getBoolean("Revert"); + revertTime = cuttingConfig.getLong("RevertTime"); + cuttableBlocks = loadCuttableBlocks(cuttingConfig.getStringList("Materials")); + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + + if (travelled >= range) { + remove(); + return; + } + + progressBlade(); + } + + private void progressBlade() { + for (int j = 0; j < 2; j++) { + if (!moveAndCheckCollision()) { + return; + } + + double pitch = -location.getPitch(); + Location lastLoc = location.clone(); + + for (double i = -90 + pitch; i <= 90 + pitch; i += 8) { + Location tempLoc = calculateParticleLocation(i); + playAirbendingParticles(tempLoc, 1, (float) Math.random() / 2, (float) Math.random() / 2, (float) Math.random() / 2); + + if (j == 0 && blockCuttingEnabled && cuttableBlocks.contains(tempLoc.getBlock().getType()) && !RegionProtection.isRegionProtected(this.player, tempLoc)) { + if (revertCutBlocks) { + new TempBlock(tempLoc.getBlock(), Material.AIR.createBlockData(), revertTime); + } else { + tempLoc.getBlock().breakNaturally(); + } + } + + if (j == 0 && !lastLoc.getBlock().getLocation().equals(tempLoc.getBlock().getLocation())) { + if (handleEntityCollision(tempLoc)) { + return; + } + lastLoc = tempLoc; + } + } + } + } + + private boolean moveAndCheckCollision() { + location = location.add(direction.multiply(speed)); + playAirbendingSound(location); + travelled += speed; + growth += 0.125; + + if (travelled >= range || + !isTransparent(location.getBlock()) || + RegionProtection.isRegionProtected(player, player.getLocation(), this)) { + remove(); + return false; + } + return true; + } + + private Location calculateParticleLocation(double angle) { + Location tempLoc = location.clone(); + tempLoc.setPitch(0); + Vector tempDir = tempLoc.getDirection().clone(); + tempDir.setY(0); + Vector newDir = tempDir.clone().multiply(growth * Math.cos(Math.toRadians(angle))); + tempLoc.add(newDir); + tempLoc.setY(tempLoc.getY() + (growth * Math.sin(Math.toRadians(angle)))); + return tempLoc; + } + + private boolean handleEntityCollision(Location tempLoc) { + return CollisionDetector.checkEntityCollisions(player, new Sphere(tempLoc.toVector(), entityCollisionRadius), entity -> { + DamageHandler.damageEntity(entity, damage, this); + + if (knockback > 0) { + Vector knockDir = entity.getLocation().toVector().subtract(location.toVector()).normalize(); + entity.setVelocity(entity.getVelocity().add(knockDir.multiply(knockback))); + } + + remove(); + return true; + }); + } + + private Set loadCuttableBlocks(List entries) { + Set result = new HashSet<>(); + for (String entry : entries) { + if (entry.startsWith("#")) { + String tagKey = entry.substring(1).toLowerCase(); + NamespacedKey ns = NamespacedKey.minecraft(tagKey); + Tag tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, ns, Material.class); + if (tag != null) tag.getValues().forEach(result::add); + } else { + try { + result.add(Material.valueOf(entry.toUpperCase())); + } catch (IllegalArgumentException ignored) {} + } + } + return result; + } + + @Override + public Player getPlayer() { + return player; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public List getLocations() { + List locations = new ArrayList<>(); + + double pitch = -location.getPitch(); + + for (double i = -90 + pitch; i <= 90 + pitch; i += 8) { + Location tempLoc = location.clone(); + tempLoc.setPitch(0); + + Vector tempDir = tempLoc.getDirection().clone(); + tempDir.setY(0); + + Vector newDir = tempDir.clone().multiply(growth * Math.cos(Math.toRadians(i))); + tempLoc.add(newDir); + tempLoc.setY(tempLoc.getY() + (growth * Math.sin(Math.toRadians(i)))); + + locations.add(tempLoc); + } + + return locations; + } + + @Override + public double getCollisionRadius() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getDouble("Abilities.Air.AirBlade.AbilityCollisionRadius"); + } + + public long getCooldown() { + return cooldown; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + @Override + public String getName() { + return "AirBlade"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return false; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Air.AirBlade.Description"); + } + + public Vector getDirection() { + return direction; + } + + public void setDirection(Vector direction) { + this.direction = direction; + } + + public double getTravelled() { + return travelled; + } + + public void setTravelled(double travelled) { + this.travelled = travelled; + } + + public double getGrowth() { + return growth; + } + + public void setGrowth(double growth) { + this.growth = growth; + } + + public double getRange() { + return range; + } + + public void setRange(double range) { + this.range = range; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public double getEntityCollisionRadius() { + return entityCollisionRadius; + } + + public void setEntityCollisionRadius(double entityCollisionRadius) { + this.entityCollisionRadius = entityCollisionRadius; + } + + public double getSpeed() { + return speed; + } + + public void setSpeed(double speed) { + this.speed = speed; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Air.AirBlade.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/airbending/AirBreath.java b/src/com/jedk1/jedcore/ability/airbending/AirBreath.java index d563d70..497af20 100644 --- a/src/com/jedk1/jedcore/ability/airbending/AirBreath.java +++ b/src/com/jedk1/jedcore/ability/airbending/AirBreath.java @@ -11,10 +11,7 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - -import org.bukkit.Color; import org.bukkit.Location; -import org.bukkit.Particle; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.ArmorStand; @@ -27,37 +24,30 @@ public class AirBreath extends AirAbility implements AddonAbility { - private boolean isAvatar; - - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.DURATION) - private long duration; private int particles; - private boolean coolLava; private boolean extinguishFire; private boolean extinguishMobs; - private boolean damageEnabled; + private double launch; + private boolean regenOxygen; + private boolean avatarAmplify; + private int avatarRange; + private double avatarKnockback; + + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.DURATION) + private long duration; @Attribute(Attribute.DAMAGE) private double playerDamage; @Attribute(Attribute.DAMAGE) private double mobDamage; - @Attribute(Attribute.KNOCKBACK) private double knockback; @Attribute(Attribute.RANGE) private int range; - private double launch; - - private boolean regenOxygen; - - private boolean avatarAmplify; - private int avatarRange; - private double avatarKnockback; - public AirBreath(Player player) { super(player); if (!bPlayer.canBend(this)) { @@ -65,8 +55,8 @@ public AirBreath(Player player) { } setFields(); - isAvatar = bPlayer.isAvatarState(); - if (isAvatar && avatarAmplify) { + + if (bPlayer.isAvatarState() && avatarAmplify) { range = avatarRange; knockback = avatarKnockback; } @@ -100,16 +90,19 @@ public void progress() { remove(); return; } + if (!(bPlayer.getBoundAbility() instanceof AirBreath)) { bPlayer.addCooldown(this); remove(); return; } + if (!player.isSneaking()) { bPlayer.addCooldown(this); remove(); return; } + if (System.currentTimeMillis() < getStartTime() + duration) { playAirbendingSound(player.getLocation()); createBeam(); @@ -121,9 +114,11 @@ public void progress() { private boolean isLocationSafe(Location loc) { Block block = loc.getBlock(); + if (RegionProtection.isRegionProtected(player, loc, this)) { return false; } + return isTransparent(block); } @@ -139,62 +134,91 @@ private void createBeam() { size += 0.005; damageregion += 0.01; - if (!isLocationSafe(loc)) { - if (!isTransparent(loc.getBlock())) { - if (player.getLocation().getPitch() > 30) { - GeneralMethods.setVelocity(this, player, player.getLocation().getDirection().multiply(-launch)); - } - } + if (!handleLocationSafety(loc)) { return; } - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(loc, damageregion)) { - if (entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand)) { - if (RegionProtection.isRegionProtected(this, entity.getLocation()) || ((entity instanceof Player) && Commands.invincible.contains(entity.getName()))){ - continue; - } - if (entity instanceof LivingEntity) { - if (damageEnabled) { - if (entity instanceof Player) - DamageHandler.damageEntity(entity, playerDamage, this); - else - DamageHandler.damageEntity(entity, mobDamage, this); - } - - if (regenOxygen && isWater(entity.getLocation().getBlock())) { - if (!((LivingEntity) entity).hasPotionEffect(PotionEffectType.WATER_BREATHING)) - ((LivingEntity) entity).addPotionEffect(new PotionEffect(PotionEffectType.WATER_BREATHING, 100, 2)); - } - - if (extinguishMobs) - entity.setFireTicks(0); - } - - dir.multiply(knockback); - GeneralMethods.setVelocity(this, entity, dir); - } + handleEntityCollisions(loc, dir, damageregion); + displayBeamParticles(loc, size); + handleBlockEffects(); + } + } + + private boolean handleLocationSafety(Location loc) { + if (!isLocationSafe(loc)) { + if (!isTransparent(loc.getBlock()) && player.getLocation().getPitch() > 30) { + GeneralMethods.setVelocity(this, player, player.getLocation().getDirection().multiply(-launch)); } + return false; + } + return true; + } - if (isWater(loc.getBlock())) { - ParticleEffect.WATER_BUBBLE.display(loc, particles, Math.random(), Math.random(), Math.random(), size); + private void handleEntityCollisions(Location loc, Vector dir, double damageregion) { + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(loc, damageregion)) { + if (isValidTarget(entity)) { + if (isEntityProtected(entity)) { + continue; + } + applyEntityEffects(entity, dir); } + } + } - JCMethods.extinguishBlocks(player, "AirBreath", range, 2, extinguishFire, coolLava); + private boolean isValidTarget(Entity entity) { + return entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand); + } - if (getAirbendingParticles() == ParticleEffect.CLOUD) { - ParticleEffect.CLOUD.display(loc, particles, Math.random(), Math.random(), Math.random(), size); - JCMethods.displayColoredParticles("#FFFFFF", loc, particles, Math.random(), Math.random(), Math.random(), 0f); - JCMethods.displayColoredParticles("#FFFFFF", player.getLocation(), particles, Math.random(), Math.random(), Math.random(), size, 50); + private boolean isEntityProtected(Entity entity) { + return RegionProtection.isRegionProtected(this, entity.getLocation()) || (entity instanceof Player && Commands.invincible.contains(entity.getName())); + } + + private void applyEntityEffects(Entity entity, Vector dir) { + if (entity instanceof LivingEntity livingEntity) { + applyDamage(livingEntity); + applyOxygenRegen(livingEntity); + if (extinguishMobs) { + livingEntity.setFireTicks(0); + } + } + dir.multiply(knockback); + GeneralMethods.setVelocity(this, entity, dir); + } + + private void applyDamage(LivingEntity entity) { + if (damageEnabled) { + if (entity instanceof Player) { + DamageHandler.damageEntity(entity, playerDamage, this); } else { - getAirbendingParticles().display(loc, particles, Math.random(), Math.random(), Math.random(), size); + DamageHandler.damageEntity(entity, mobDamage, this); } } } - /* - * @Override public void remove() { if (player.isOnline()) { - * bPlayer.addCooldown("AirBreath", cooldown); } super.remove(); } - */ + private void applyOxygenRegen(LivingEntity entity) { + if (regenOxygen && isWater(entity.getLocation().getBlock()) && !entity.hasPotionEffect(PotionEffectType.WATER_BREATHING)) { + entity.addPotionEffect(new PotionEffect(PotionEffectType.WATER_BREATHING, 100, 2)); + } + } + + private void displayBeamParticles(Location loc, double size) { + if (isWater(loc.getBlock())) { + ParticleEffect.WATER_BUBBLE.display(loc, particles, Math.random(), Math.random(), Math.random(), size); + } + + ParticleEffect mainParticle = getAirbendingParticles(); + if (mainParticle == ParticleEffect.CLOUD) { + ParticleEffect.CLOUD.display(loc, particles, Math.random(), Math.random(), Math.random(), size); + JCMethods.displayColoredParticles("#FFFFFF", loc, particles, Math.random(), Math.random(), Math.random(), 0f); + JCMethods.displayColoredParticles("#FFFFFF", player.getLocation(), particles, Math.random(), Math.random(), Math.random(), size, 50); + } else if (mainParticle != null) { + mainParticle.display(loc, particles, Math.random(), Math.random(), Math.random(), size); + } + } + + private void handleBlockEffects() { + JCMethods.extinguishBlocks(player, "AirBreath", range, 2, extinguishFire, coolLava); + } @Override public long getCooldown() { @@ -368,4 +392,4 @@ public boolean isEnabled() { ConfigurationSection config = JedCoreConfig.getConfig(this.player); return config.getBoolean("Abilities.Air.AirBreath.Enabled"); } -} \ No newline at end of file +} diff --git a/src/com/jedk1/jedcore/ability/airbending/AirGlide.java b/src/com/jedk1/jedcore/ability/airbending/AirGlide.java index 054af57..77c0b1d 100644 --- a/src/com/jedk1/jedcore/ability/airbending/AirGlide.java +++ b/src/com/jedk1/jedcore/ability/airbending/AirGlide.java @@ -7,7 +7,6 @@ import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.AirAbility; import com.projectkorra.projectkorra.airbending.AirSpout; - import com.projectkorra.projectkorra.attribute.Attribute; import org.bukkit.Location; import org.bukkit.block.BlockFace; @@ -17,19 +16,20 @@ public class AirGlide extends AirAbility implements AddonAbility { + private double fallSpeed; + private int particles; + private boolean airspout; + private long lastCooldown; + private boolean progressing; // The player must touch the ground for the cooldown to start if this is true. private boolean requireGround; + @Attribute(Attribute.SPEED) private double speed; - private double fallSpeed; - private int particles; - private boolean airspout; @Attribute(Attribute.COOLDOWN) private long cooldown; @Attribute(Attribute.DURATION) private long duration; - private long lastCooldown; - private boolean progressing; public AirGlide(Player player) { super(player); @@ -76,13 +76,10 @@ public void progress() { } if (CollisionDetector.isOnGround(this.player)) { - // Flip this so remove() actually removes the instance. this.requireGround = false; remove(); } else { - // Limit how frequently addCooldown is called so bending board isn't spammed with updates. if (time > lastCooldown + cooldown / 2) { - // Keep resetting the cooldown until the player touches the ground. bPlayer.addCooldown(this); lastCooldown = time; } @@ -90,6 +87,7 @@ public void progress() { } } + @SuppressWarnings("deprecation") private void update(long time) { if (this.duration > 0 && time >= this.getStartTime() + this.duration) { remove(); @@ -113,12 +111,15 @@ private void update(long time) { if (!player.isOnGround()) { Location firstLocation = player.getEyeLocation(); + Vector directionVector = firstLocation.getDirection().normalize(); double distanceFromPlayer = speed; + Vector shootFromPlayer = new Vector(directionVector.getX() * distanceFromPlayer, -fallSpeed, directionVector.getZ() * distanceFromPlayer); firstLocation.add(shootFromPlayer.getX(), shootFromPlayer.getY(), shootFromPlayer.getZ()); GeneralMethods.setVelocity(this, player, shootFromPlayer); + playAirbendingParticles(player.getLocation(), particles); } else if (!isTransparent(player.getLocation().getBlock().getRelative(BlockFace.DOWN))) { remove(); diff --git a/src/com/jedk1/jedcore/ability/airbending/AirPunch.java b/src/com/jedk1/jedcore/ability/airbending/AirPunch.java index d776d46..eac83b2 100644 --- a/src/com/jedk1/jedcore/ability/airbending/AirPunch.java +++ b/src/com/jedk1/jedcore/ability/airbending/AirPunch.java @@ -11,12 +11,12 @@ import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -25,6 +25,9 @@ public class AirPunch extends AirAbility implements AddonAbility { private final Map locations = new ConcurrentHashMap<>(); + private int shots; + private long lastShotTime; + @Attribute(Attribute.COOLDOWN) private long cooldown; private long threshold; @@ -35,9 +38,6 @@ public class AirPunch extends AirAbility implements AddonAbility { @Attribute("CollisionRadius") private double entityCollisionRadius; - private int shots; - private long lastShotTime; - public AirPunch(Player player) { super(player); @@ -54,8 +54,8 @@ public AirPunch(Player player) { setFields(); start(); - if (!isRemoved()) - createShot(); + + if (!isRemoved()) createShot(); } public void setFields() { @@ -107,38 +107,70 @@ private void createShot() { } private void progressShots() { - for (Location l : locations.keySet()) { - Location loc = l.clone(); - double dist = locations.get(l); - boolean cancel = false; - for (int i = 0; i < 3; i++) { - dist++; - if (cancel || dist >= range) { - cancel = true; - break; - } - loc = loc.add(loc.getDirection().clone().multiply(1)); - if (GeneralMethods.isSolid(loc.getBlock()) || isWater(loc.getBlock()) || RegionProtection.isRegionProtected(player, loc, this)) { - cancel = true; - break; - } + Iterator> iterator = locations.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + Location originalLoc = entry.getKey(); + double dist = entry.getValue(); + ShotResult result = simulateShotProgression(originalLoc, dist); - getAirbendingParticles().display(loc, 2, Math.random() / 5, Math.random() / 5, Math.random() / 5, 0.0); - playAirbendingSound(loc); + iterator.remove(); - cancel = CollisionDetector.checkEntityCollisions(player, new Sphere(loc.toVector(), entityCollisionRadius), (entity) -> { - DamageHandler.damageEntity(entity, damage, this); - return true; - }); + if (result.moved) { + locations.put(result.newLoc, result.newDist); } + } + } - if (cancel) { - locations.remove(l); + private record ShotResult(Location newLoc, double newDist, boolean moved) {} + + private ShotResult simulateShotProgression(Location startLoc, double startDist) { + Location loc = startLoc.clone(); + double dist = startDist; + boolean shouldRemove = false; + boolean moved = false; + + for (int i = 0; i < 3 && !shouldRemove; i++) { + dist++; + if (dist >= range) { + shouldRemove = true; } else { - locations.remove(l); - locations.put(loc, dist); + Location nextLoc = calculateNextLocation(loc); + if (isPathBlocked(nextLoc)) { + shouldRemove = true; + } else { + applyShotEffects(nextLoc); + if (checkAndHandleCollision(nextLoc)) { + shouldRemove = true; + } else { + loc = nextLoc; + moved = true; + } + } } } + + return new ShotResult(loc, dist, moved); + } + + private Location calculateNextLocation(Location currentLocation) { + return currentLocation.add(currentLocation.getDirection().clone().multiply(1)); + } + + private boolean isPathBlocked(Location location) { + return GeneralMethods.isSolid(location.getBlock()) || isWater(location.getBlock()) || RegionProtection.isRegionProtected(player, location, this); + } + + private void applyShotEffects(Location location) { + getAirbendingParticles().display(location, 2, Math.random() / 5, Math.random() / 5, Math.random() / 5, 0.0); + playAirbendingSound(location); + } + + private boolean checkAndHandleCollision(Location location) { + return CollisionDetector.checkEntityCollisions(player, new Sphere(location.toVector(), entityCollisionRadius), entity -> { + DamageHandler.damageEntity(entity, damage, this); + return true; + }); } @Override diff --git a/src/com/jedk1/jedcore/ability/airbending/Meditate.java b/src/com/jedk1/jedcore/ability/airbending/Meditate.java index 8f40caa..c240829 100644 --- a/src/com/jedk1/jedcore/ability/airbending/Meditate.java +++ b/src/com/jedk1/jedcore/ability/airbending/Meditate.java @@ -7,7 +7,6 @@ import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.SpiritualAbility; import com.projectkorra.projectkorra.attribute.Attribute; - import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.configuration.ConfigurationSection; @@ -18,19 +17,19 @@ public class Meditate extends SpiritualAbility implements AddonAbility { private double startHealth; - private String unfocusMsg; private long warmup; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.DURATION) - private int boostDuration; private int particleDensity; private boolean lossFocusMessage; private int absorptionBoost; private int speedBoost; private int jumpBoost; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.DURATION) + private int boostDuration; + public Meditate(Player player) { super(player); if (!bPlayer.canBend(this)) { @@ -63,20 +62,23 @@ public void progress() { remove(); return; } + if (!bPlayer.canBendIgnoreCooldowns(this)) { remove(); return; } + if (player.getHealth() < startHealth) { - if (lossFocusMessage) { - player.sendMessage(Element.SPIRITUAL.getColor() + unfocusMsg); - } + if (lossFocusMessage) player.sendMessage(Element.SPIRITUAL.getColor() + unfocusMsg); remove(); return; } + if (System.currentTimeMillis() > getStartTime() + warmup) { player.spawnParticle(Particle.ELECTRIC_SPARK, player.getLocation(), 3, 0.5, 0.5, 0.5, 0.003F); + JCMethods.displayColoredParticles("#FFFFFF", player.getLocation(), particleDensity, Math.random(), Math.random(), Math.random(), 0f); + if (!player.isSneaking()) { bPlayer.addCooldown(this); givePlayerBuffs(); @@ -93,6 +95,7 @@ private void givePlayerBuffs() { if (player.hasPotionEffect(PotionEffectType.SPEED)) { player.removePotionEffect(PotionEffectType.SPEED); } + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, boostDuration/50, speedBoost - 1)); JedCore.plugin.getPotionEffectAdapter().applyJumpBoost(player, boostDuration, jumpBoost); @@ -100,6 +103,7 @@ private void givePlayerBuffs() { if (player.hasPotionEffect(PotionEffectType.ABSORPTION)) { player.removePotionEffect(PotionEffectType.ABSORPTION); } + player.addPotionEffect(new PotionEffect(PotionEffectType.ABSORPTION, boostDuration/50, absorptionBoost - 1)); } diff --git a/src/com/jedk1/jedcore/ability/airbending/SonicBlast.java b/src/com/jedk1/jedcore/ability/airbending/SonicBlast.java index 0edeb08..5ae22f2 100644 --- a/src/com/jedk1/jedcore/ability/airbending/SonicBlast.java +++ b/src/com/jedk1/jedcore/ability/airbending/SonicBlast.java @@ -10,7 +10,6 @@ import com.projectkorra.projectkorra.ability.CoreAbility; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.configuration.ConfigurationSection; @@ -26,6 +25,9 @@ public class SonicBlast extends AirAbility implements AddonAbility { private Vector direction; private boolean isCharged; private int travelled; + private int nauseaDur; + private int blindDur; + private boolean chargeSwapping; @Attribute(Attribute.DAMAGE) private double damage; @@ -37,9 +39,6 @@ public class SonicBlast extends AirAbility implements AddonAbility { private long cooldown; @Attribute("WarmUp") private long warmup; - private int nauseaDur; - private int blindDur; - private boolean chargeSwapping; public SonicBlast(Player player) { super(player); @@ -67,40 +66,52 @@ public void setFields() { @Override public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); + if (!checkPlayerState()) { return; } - CoreAbility boundAbility = bPlayer.getBoundAbility(); - - if (!this.chargeSwapping && this.travelled == 0 && !(boundAbility instanceof SonicBlast)) { + if (!canStartAbility()) { remove(); return; } if (player.isSneaking() && travelled == 0) { - direction = player.getEyeLocation().getDirection().normalize(); + handleCharging(); + } else { + handleProgression(); + } + } + + private boolean checkPlayerState() { + return !player.isDead() && player.isOnline(); + } + + private boolean canStartAbility() { + CoreAbility boundAbility = bPlayer.getBoundAbility(); + return chargeSwapping || travelled > 0 || boundAbility instanceof SonicBlast; + } - if (isCharged) { - playAirbendingParticles(player.getLocation().add(0, 1, 0), 5, (float) Math.random(), (float) Math.random(), (float) Math.random()); - } else if (System.currentTimeMillis() > getStartTime() + warmup) { - isCharged = true; + private void handleCharging() { + direction = player.getEyeLocation().getDirection().normalize(); + if (isCharged) { + playAirbendingParticles(player.getLocation().add(0, 1, 0), 5, (float) Math.random(), (float) Math.random(), (float) Math.random()); + } else if (System.currentTimeMillis() > getStartTime() + warmup) { + isCharged = true; + } + } + + private void handleProgression() { + if (isCharged) { + if (!bPlayer.isOnCooldown(this)) { + bPlayer.addCooldown(this); } - } else { - if (isCharged) { - if (!bPlayer.isOnCooldown(this)) { - bPlayer.addCooldown(this); - } - - if (travelled < range && isLocationSafe()) { - advanceLocation(); - } else { - remove(); - } + if (travelled < range && isLocationSafe()) { + advanceLocation(); } else { remove(); } + } else { + remove(); } } @@ -129,7 +140,7 @@ private void advanceLocation() { playAirbendingParticles(temp, 1, 0, 0, 0); } - boolean hit = CollisionDetector.checkEntityCollisions(player, new Sphere(location.toVector(), entityCollisionRadius), (entity) -> { + boolean hit = CollisionDetector.checkEntityCollisions(player, new Sphere(location.toVector(), entityCollisionRadius), entity -> { DamageHandler.damageEntity(entity, damage, this); LivingEntity lE = (LivingEntity) entity; diff --git a/src/com/jedk1/jedcore/ability/airbending/combo/AirSlam.java b/src/com/jedk1/jedcore/ability/airbending/combo/AirSlam.java index de6bbf3..f2f99b3 100644 --- a/src/com/jedk1/jedcore/ability/airbending/combo/AirSlam.java +++ b/src/com/jedk1/jedcore/ability/airbending/combo/AirSlam.java @@ -13,8 +13,6 @@ import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.object.HorizontalVelocityTracker; import com.projectkorra.projectkorra.region.RegionProtection; -import com.projectkorra.projectkorra.util.ClickType; - import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Entity; @@ -44,14 +42,16 @@ public AirSlam(Player player) { setFields(); - Entity target = GeneralMethods.getTargetedEntity(player, range, new ArrayList<>()); - if (!(target instanceof LivingEntity) - || RegionProtection.isRegionProtected(this, target.getLocation()) - || ((target instanceof Player) && Commands.invincible.contains(target.getName()))) + Entity targetEntity = GeneralMethods.getTargetedEntity(player, range, new ArrayList<>()); + if (!(targetEntity instanceof LivingEntity) + || RegionProtection.isRegionProtected(this, targetEntity.getLocation()) + || ((targetEntity instanceof Player) && Commands.invincible.contains(targetEntity.getName()))) return; - this.target = (LivingEntity) target; + + this.target = (LivingEntity) targetEntity; start(); + if (!isRemoved()) { bPlayer.addCooldown(this); GeneralMethods.setVelocity(this, target, new Vector(0, 2, 0)); @@ -72,6 +72,7 @@ public void progress() { remove(); return; } + if (System.currentTimeMillis() > getStartTime() + 50) { Vector dir = player.getLocation().getDirection(); GeneralMethods.setVelocity(this, target, new Vector(dir.getX(), 0.05, dir.getZ()).multiply(power)); @@ -79,10 +80,12 @@ public void progress() { new ThrownEntityTracker(this, target, player, 0L); target.setFallDistance(0); } + if (System.currentTimeMillis() > getStartTime() + 400) { remove(); return; } + playAirbendingParticles(target.getLocation(), 10); } @@ -182,4 +185,4 @@ public boolean isEnabled() { ConfigurationSection config = JedCoreConfig.getConfig(this.player); return config.getBoolean("Abilities.Air.AirCombo.AirSlam.Enabled"); } -} \ No newline at end of file +} diff --git a/src/com/jedk1/jedcore/ability/airbending/combo/SwiftStream.java b/src/com/jedk1/jedcore/ability/airbending/combo/SwiftStream.java index f5ce42c..0b2929c 100644 --- a/src/com/jedk1/jedcore/ability/airbending/combo/SwiftStream.java +++ b/src/com/jedk1/jedcore/ability/airbending/combo/SwiftStream.java @@ -10,8 +10,6 @@ import com.projectkorra.projectkorra.ability.util.ComboUtil; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.object.HorizontalVelocityTracker; -import com.projectkorra.projectkorra.util.ClickType; - import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Entity; @@ -24,22 +22,25 @@ public class SwiftStream extends FlightAbility implements AddonAbility, ComboAbility { + private final List affectedEntities = new ArrayList<>(); + @Attribute(Attribute.COOLDOWN) public long cooldown; + @Attribute("DragFactor") public double dragFactor; @Attribute(Attribute.DURATION) public long duration; - private final List affectedEntities = new ArrayList<>(); - public SwiftStream(Player player) { super(player); + if (!bPlayer.canBendIgnoreBinds(this) || !bPlayer.canUseFlight()) { return; } setFields(); start(); + if (!isRemoved()) { launch(); bPlayer.addCooldown(this); @@ -65,17 +66,16 @@ public void launch() { public void affectNearby() { for (Entity e : GeneralMethods.getEntitiesAroundPoint(player.getLocation(), 2.5)) { - if (e instanceof LivingEntity && !affectedEntities.contains(e) && e.getEntityId() != player.getEntityId()) { + if (e instanceof LivingEntity livingEntity && !affectedEntities.contains(e) && e.getEntityId() != player.getEntityId()) { Vector v = player.getVelocity().clone(); - v = v.multiply(dragFactor); - v = v.setY(player.getVelocity().getY()); - v = v.add(new Vector(0, 0.15, 0)); GeneralMethods.setVelocity(this, e, v); - affectedEntities.add((LivingEntity) e); + + affectedEntities.add(livingEntity); + new HorizontalVelocityTracker(e, player, 200, this); } } @@ -194,4 +194,4 @@ public boolean isEnabled() { ConfigurationSection config = JedCoreConfig.getConfig(this.player); return config.getBoolean("Abilities.Air.AirCombo.SwiftStream.Enabled"); } -} \ No newline at end of file +} diff --git a/src/com/jedk1/jedcore/ability/avatar/SpiritBeam.java b/src/com/jedk1/jedcore/ability/avatar/SpiritBeam.java index 923b772..689a3b5 100644 --- a/src/com/jedk1/jedcore/ability/avatar/SpiritBeam.java +++ b/src/com/jedk1/jedcore/ability/avatar/SpiritBeam.java @@ -11,13 +11,9 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - -import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Particle; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -25,33 +21,31 @@ public class SpiritBeam extends AvatarAbility implements AddonAbility { - private Location location; + private Location location; private Vector direction; + private boolean damagesBlocks; + private long regen; + private boolean avatarOnly; + @Attribute(Attribute.DURATION) private long duration; @Attribute(Attribute.COOLDOWN) private long cooldown; @Attribute(Attribute.RANGE) private double range; - private boolean avatarOnly; @Attribute(Attribute.DAMAGE) private double damage; - private boolean damagesBlocks; - private long regen; @Attribute(Attribute.RADIUS) private double radius; public SpiritBeam(Player player) { super(player); - if (bPlayer.isOnCooldown(this)) { - return; - } + + if (bPlayer.isOnCooldown(this)) return; setFields(); - if (avatarOnly && !bPlayer.isAvatarState()) { - return; - } + if (avatarOnly && !bPlayer.isAvatarState()) return; start(); } @@ -75,64 +69,93 @@ public void progress() { remove(); return; } + if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { bPlayer.addCooldown(this); remove(); return; } + if (System.currentTimeMillis() > getStartTime() + duration) { bPlayer.addCooldown(this); remove(); return; } + if (!player.isSneaking()) { bPlayer.addCooldown(this); remove(); return; } + if (avatarOnly && !bPlayer.isAvatarState()) { bPlayer.addCooldown(this); remove(); return; } + createBeam(); } private void createBeam() { location = player.getLocation().add(0, 1.2, 0); - direction = location.getDirection(); + Vector beamDirection = location.getDirection().normalize().multiply(0.5); + for (double i = 0; i < range; i += 0.5) { - location = location.add(direction.multiply(0.5).normalize()); + location = location.add(beamDirection); - if (RegionProtection.isRegionProtected(player, location, this)) { + if (isBeamObstructed(location)) { return; } - JCMethods.displayColoredParticles("#A020F0", location, 1, 0f, 0f, 0f, 0f); - JCMethods.displayColoredParticles("#A020F0", location, 1, (float) Math.random() / 3, (float) Math.random() / 3, (float) Math.random() / 3, 0f); + displayBeamParticles(location, beamDirection); + JCMethods.emitLight(location); + damageNearbyEntities(location); + + if (handleBlockCollision(location)) { + return; + } + } + } - ParticleEffect.BLOCK_CRACK.display(location, 1,(float) Math.random() / 3, (float) Math.random() / 3, (float) Math.random() / 3, 0.1F, Material.NETHER_PORTAL.createBlockData()); - ParticleEffect.BLOCK_CRACK.display(location, 1, direction.getX(), direction.getY(), direction.getZ(), 0.1F, Material.NETHER_PORTAL.createBlockData()); + private boolean isBeamObstructed(Location location) { + return RegionProtection.isRegionProtected(player, location, this); + } - JCMethods.emitLight(location); + private void displayBeamParticles(Location location, Vector direction) { + String purple = "#A020F0"; + JCMethods.displayColoredParticles(purple, location, 1, 0f, 0f, 0f, 0f); + JCMethods.displayColoredParticles(purple, location, 1, (float) Math.random() / 3, (float) Math.random() / 3, (float) Math.random() / 3, 0f); - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand)) { - entity.setFireTicks(100); - DamageHandler.damageEntity(entity, damage, this); - } + float randomOffset = (float) Math.random() / 3; + ParticleEffect.BLOCK_CRACK.display(location, 1, randomOffset, randomOffset, randomOffset, 0.1F, Material.NETHER_PORTAL.createBlockData()); + ParticleEffect.BLOCK_CRACK.display(location, 1, (float) direction.getX(), (float) direction.getY(), (float) direction.getZ(), 0.1F, Material.NETHER_PORTAL.createBlockData()); + } + + private void damageNearbyEntities(Location location) { + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2)) { + if (entity instanceof LivingEntity livingEntity && livingEntity.getEntityId() != player.getEntityId()) { + livingEntity.setFireTicks(100); + DamageHandler.damageEntity(livingEntity, damage, this); } + } + } - if (location.getBlock().getType().isSolid()) { - location.getWorld().createExplosion(location, 0F); - if (damagesBlocks) { - //new TempExplosion(player, location.getBlock(), "SpiritBeam", radius, regen, damage, false); - for (Location loc : GeneralMethods.getCircle(location, (int) radius, 0, false, true, 0)) { - if (JCMethods.isUnbreakable(loc.getBlock())) continue; - new RegenTempBlock(loc.getBlock(), Material.AIR, Material.AIR.createBlockData(), regen, false); - } - } - return; + private boolean handleBlockCollision(Location location) { + if (location.getBlock().getType().isSolid()) { + location.getWorld().createExplosion(location, 0F); + if (damagesBlocks) { + damageBlocksInRadius(location); + } + return true; + } + return false; + } + + private void damageBlocksInRadius(Location center) { + for (Location loc : GeneralMethods.getCircle(center, (int) radius, 0, false, true, 0)) { + if (!JCMethods.isUnbreakable(loc.getBlock())) { + new RegenTempBlock(loc.getBlock(), Material.AIR, Material.AIR.createBlockData(), regen, false); } } } diff --git a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESAir.java b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESAir.java index bff4481..a7e0820 100644 --- a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESAir.java +++ b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESAir.java @@ -10,7 +10,6 @@ import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.ArmorStand; @@ -36,22 +35,30 @@ public class ESAir extends AvatarAbility implements AddonAbility { public ESAir(Player player) { super(player); + if (!hasAbility(player, ElementSphere.class)) { return; } + ElementSphere currES = getAbility(player, ElementSphere.class); if (currES.getAirUses() == 0) { return; } + if (bPlayer.isOnCooldown("ESAir")) { return; } + setFields(); + if (RegionProtection.isRegionProtected(this, player.getTargetBlock(getTransparentMaterialSet(), (int) range).getLocation())) { return; } + location = player.getEyeLocation().clone().add(player.getEyeLocation().getDirection().multiply(1)); + start(); + if (!isRemoved()) { bPlayer.addCooldown("ESAir", getCooldown()); currES.setAirUses(currES.getAirUses() - 1); @@ -74,23 +81,27 @@ public void progress() { remove(); return; } + if (travelled >= range) { remove(); return; } + advanceAttack(); } private void advanceAttack() { for (int i = 0; i < speed; i++) { travelled++; - if (travelled >= range) - return; + if (travelled >= range) return; + location = location.add(location.getDirection().clone().multiply(1)); + if (RegionProtection.isRegionProtected(this, location)) { travelled = range; return; } + if (GeneralMethods.isSolid(location.getBlock()) || isWater(location.getBlock())) { travelled = range; return; @@ -100,7 +111,11 @@ private void advanceAttack() { AirAbility.playAirbendingSound(location); for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.5)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand) && !RegionProtection.isRegionProtected(this, entity.getLocation()) && !((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() + && !(entity instanceof ArmorStand) + && !RegionProtection.isRegionProtected(this, entity.getLocation()) + && !((entity instanceof Player targetPlayer) + && Commands.invincible.contains((targetPlayer).getName()))) { DamageHandler.damageEntity(entity, damage, this); GeneralMethods.setVelocity(this, entity, location.getDirection().multiply(knockback)); travelled = range; diff --git a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESEarth.java b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESEarth.java index 9113ecf..05832ec 100644 --- a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESEarth.java +++ b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESEarth.java @@ -13,7 +13,6 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - import com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.Material; @@ -21,204 +20,196 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import java.util.Arrays; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class ESEarth extends AvatarAbility implements AddonAbility { - private long revertDelay; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute("Size") - private int impactSize; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - private TempFallingBlock tfb; - - static Random rand = new Random(); - - public ESEarth(Player player) { - super(player); - if (!hasAbility(player, ElementSphere.class)) { - return; - } - ElementSphere currES = getAbility(player, ElementSphere.class); - if (currES.getEarthUses() == 0) { - return; - } - if (bPlayer.isOnCooldown("ESEarth")) { - return; - } - if (RegionProtection.isRegionProtected(this, player.getTargetBlock(getTransparentMaterialSet(), 40).getLocation())) { - return; - } - setFields(); - start(); - if (!isRemoved()) { - bPlayer.addCooldown("ESEarth", getCooldown()); - currES.setEarthUses(currES.getEarthUses() - 1); - Location location = player.getEyeLocation().clone().add(player.getEyeLocation().getDirection().multiply(1)); - tfb = new TempFallingBlock(location, Material.DIRT.createBlockData(), location.getDirection().multiply(3), this); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - revertDelay = config.getLong("Abilities.Avatar.ElementSphere.Earth.ImpactRevert"); - damage = config.getDouble("Abilities.Avatar.ElementSphere.Earth.Damage"); - impactSize = config.getInt("Abilities.Avatar.ElementSphere.Earth.ImpactCraterSize"); - cooldown = config.getLong("Abilities.Avatar.ElementSphere.Earth.Cooldown"); - } - - @Override - public void progress() { - if (player == null || !player.isOnline()) { - tfb.remove(); - remove(); - return; - } - if (tfb.getFallingBlock().isDead()) { - remove(); - return; - } - if (RegionProtection.isRegionProtected(this, tfb.getLocation())){ - remove(); - return; - } - - EarthAbility.playEarthbendingSound(tfb.getLocation()); - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(tfb.getLocation(), 2.5)) { - if (entity instanceof LivingEntity && !(entity instanceof ArmorStand) && entity.getEntityId() != player.getEntityId() && !RegionProtection.isRegionProtected(this, entity.getLocation()) && !((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))) { - //explodeEarth(fb); - DamageHandler.damageEntity(entity, damage, this); - } - } - } - - public static void explodeEarth(TempFallingBlock tempfallingblock) { - FallingBlock fb = tempfallingblock.getFallingBlock(); - ESEarth es = (ESEarth) tempfallingblock.getAbility(); - Player player = es.getPlayer(); - - ParticleEffect.SMOKE_LARGE.display(fb.getLocation(), 0, 0, 0, 0.3F, 25); - fb.getWorld().playSound(fb.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 2f, 0.5f); - - for (Location l : GeneralMethods.getCircle(fb.getLocation(), es.impactSize, 1, false, true, 0)) { - //if (TempBlock.isTempBlock(l.getBlock())) { - // TempBlock.revertBlock(l.getBlock(), Material.AIR); - // TempBlock.removeBlock(l.getBlock()); - //} - if (isBreakable(l.getBlock()) && !RegionProtection.isRegionProtected(player, l, "ElementSphere") && EarthAbility.isEarthbendable(player, l.getBlock())) { - ParticleEffect.SMOKE_LARGE.display(l, 0, 0, 0, 0.1F, 2); - //new RegenTempBlock(l.getBlock(), Material.AIR, (byte) 0, (long) rand.nextInt((int) es.revertDelay - (int) (es.revertDelay - 1000)) + (es.revertDelay - 1000)); - new RegenTempBlock(l.getBlock(), Material.AIR, Material.AIR.createBlockData(), (long) rand.nextInt((int) es.revertDelay - (int) (es.revertDelay - 1000)) + (es.revertDelay - 1000), false); - } - - if (GeneralMethods.isSolid(l.getBlock().getRelative(BlockFace.DOWN)) && isBreakable(l.getBlock()) && ElementalAbility.isAir(l.getBlock().getType()) && rand.nextInt(20) == 0 && EarthAbility.isEarthbendable(player, l.getBlock().getRelative(BlockFace.DOWN))) { - Material type = l.getBlock().getRelative(BlockFace.DOWN).getType(); - new RegenTempBlock(l.getBlock(), type, type.createBlockData(), (long) rand.nextInt((int) es.revertDelay - (int) (es.revertDelay - 1000)) + (es.revertDelay - 1000)); - } - } - - tempfallingblock.remove(); - } - - static Material[] unbreakables = { Material.BEDROCK, Material.BARRIER, Material.NETHER_PORTAL, Material.END_PORTAL, - Material.END_PORTAL_FRAME, Material.ENDER_CHEST, Material.CHEST, Material.TRAPPED_CHEST }; - - public static boolean isBreakable(Block block) { - return !Arrays.asList(unbreakables).contains(block.getType()); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return tfb != null ? tfb.getLocation() : null; - } - - @Override - public String getName() { - return "ElementSphereEarth"; - } - - @Override - public boolean isHiddenAbility() { - return true; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return false; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - return null; - } - - public long getRevertDelay() { - return revertDelay; - } - - public void setRevertDelay(long revertDelay) { - this.revertDelay = revertDelay; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public int getImpactSize() { - return impactSize; - } - - public void setImpactSize(int impactSize) { - this.impactSize = impactSize; - } - - public TempFallingBlock getTempFallingBlock() { - return tfb; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Avatar.ElementSphere.Enabled"); - } -} + static Material[] unbreakables = { Material.BEDROCK, Material.BARRIER, Material.NETHER_PORTAL, Material.END_PORTAL, + Material.END_PORTAL_FRAME, Material.ENDER_CHEST, Material.CHEST, Material.TRAPPED_CHEST }; + + private TempFallingBlock tfb; + private long revertDelay; + + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute("Size") + private int impactSize; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + + public ESEarth(Player player) { + super(player); + if (!hasAbility(player, ElementSphere.class)) { + return; + } + ElementSphere currES = getAbility(player, ElementSphere.class); + if (currES.getEarthUses() == 0) { + return; + } + if (bPlayer.isOnCooldown("ESEarth")) { + return; + } + if (RegionProtection.isRegionProtected(this, player.getTargetBlock(getTransparentMaterialSet(), 40).getLocation())) { + return; + } + setFields(); + start(); + if (!isRemoved()) { + bPlayer.addCooldown("ESEarth", getCooldown()); + currES.setEarthUses(currES.getEarthUses() - 1); + Location location = player.getEyeLocation().clone().add(player.getEyeLocation().getDirection().multiply(1)); + tfb = new TempFallingBlock(location, Material.DIRT.createBlockData(), location.getDirection().multiply(3), this); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + revertDelay = config.getLong("Abilities.Avatar.ElementSphere.Earth.ImpactRevert"); + damage = config.getDouble("Abilities.Avatar.ElementSphere.Earth.Damage"); + impactSize = config.getInt("Abilities.Avatar.ElementSphere.Earth.ImpactCraterSize"); + cooldown = config.getLong("Abilities.Avatar.ElementSphere.Earth.Cooldown"); + } + + @Override + public void progress() { + if (player == null || !player.isOnline()) { + tfb.remove(); + remove(); + return; + } + if (tfb.getFallingBlock().isDead()) { + remove(); + return; + } + if (RegionProtection.isRegionProtected(this, tfb.getLocation())){ + remove(); + return; + } + + EarthAbility.playEarthbendingSound(tfb.getLocation()); + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(tfb.getLocation(), 2.5)) { + if (entity instanceof LivingEntity && !(entity instanceof ArmorStand) && entity.getEntityId() != player.getEntityId() && !RegionProtection.isRegionProtected(this, entity.getLocation()) && !((entity instanceof Player targetPlayer) && Commands.invincible.contains(targetPlayer.getName()))) { + DamageHandler.damageEntity(entity, damage, this); + } + } + } + + // Unused + public static void explodeEarth(TempFallingBlock tempfallingblock) { + FallingBlock fb = tempfallingblock.getFallingBlock(); + ESEarth es = (ESEarth) tempfallingblock.getAbility(); + Player player = es.getPlayer(); + + ParticleEffect.SMOKE_LARGE.display(fb.getLocation(), 0, 0, 0, 0.3F, 25); + fb.getWorld().playSound(fb.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 2f, 0.5f); + + ThreadLocalRandom rand = ThreadLocalRandom.current(); + + for (Location l : GeneralMethods.getCircle(fb.getLocation(), es.impactSize, 1, false, true, 0)) { + if (isBreakable(l.getBlock()) && !RegionProtection.isRegionProtected(player, l, "ElementSphere") && EarthAbility.isEarthbendable(player, l.getBlock())) { + ParticleEffect.SMOKE_LARGE.display(l, 0, 0, 0, 0.1F, 2); + new RegenTempBlock(l.getBlock(), Material.AIR, Material.AIR.createBlockData(), rand.nextInt((int) es.revertDelay - (int) (es.revertDelay - 1000)) + (es.revertDelay - 1000), false); + } + + if (GeneralMethods.isSolid(l.getBlock().getRelative(BlockFace.DOWN)) && isBreakable(l.getBlock()) && ElementalAbility.isAir(l.getBlock().getType()) && rand.nextInt(20) == 0 && EarthAbility.isEarthbendable(player, l.getBlock().getRelative(BlockFace.DOWN))) { + Material type = l.getBlock().getRelative(BlockFace.DOWN).getType(); + new RegenTempBlock(l.getBlock(), type, type.createBlockData(), rand.nextInt((int) es.revertDelay - (int) (es.revertDelay - 1000)) + (es.revertDelay - 1000)); + } + } + + tempfallingblock.remove(); + } + + public static boolean isBreakable(Block block) { + return !Arrays.asList(unbreakables).contains(block.getType()); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return tfb != null ? tfb.getLocation() : null; + } + + @Override + public String getName() { + return "ElementSphereEarth"; + } + + @Override + public boolean isHiddenAbility() { + return true; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return false; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + return null; + } + + public long getRevertDelay() { + return revertDelay; + } + + public void setRevertDelay(long revertDelay) { + this.revertDelay = revertDelay; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public int getImpactSize() { + return impactSize; + } + + public void setImpactSize(int impactSize) { + this.impactSize = impactSize; + } + + public TempFallingBlock getTempFallingBlock() { + return tfb; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Avatar.ElementSphere.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESFire.java b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESFire.java index a377d39..32ec393 100644 --- a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESFire.java +++ b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESFire.java @@ -4,8 +4,8 @@ import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.projectkorra.projectkorra.Element; -import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.Element.SubElement; +import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.AvatarAbility; import com.projectkorra.projectkorra.ability.BlueFireAbility; @@ -16,7 +16,6 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.BlockFace; @@ -32,6 +31,7 @@ public class ESFire extends AvatarAbility implements AddonAbility { private Location location; private Vector direction; private double travelled; + private boolean controllable; @Attribute(Attribute.COOLDOWN) private long cooldown; @@ -43,22 +43,26 @@ public class ESFire extends AvatarAbility implements AddonAbility { private long burnTime; @Attribute(Attribute.SPEED) private int speed; - private boolean controllable; public ESFire(Player player) { super(player); + if (!hasAbility(player, ElementSphere.class)) { return; } + ElementSphere currES = getAbility(player, ElementSphere.class); if (currES.getFireUses() == 0) { return; } + if (bPlayer.isOnCooldown("ESFire")) { return; } + setFields(); start(); + if (!isRemoved()) { bPlayer.addCooldown("ESFire", getCooldown()); currES.setFireUses(currES.getFireUses() - 1); @@ -82,7 +86,7 @@ public void setFields() { private void applyModifiers() { if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { - cooldown *= BlueFireAbility.getCooldownFactor(); + cooldown *= (long) BlueFireAbility.getCooldownFactor(); range *= BlueFireAbility.getRangeFactor(); damage *= BlueFireAbility.getDamageFactor(); } @@ -94,51 +98,85 @@ public void progress() { remove(); return; } + if (travelled >= range) { remove(); return; } + advanceAttack(); } private void advanceAttack() { for (int i = 0; i < speed; i++) { - travelled++; - if (travelled >= range) + if (!incrementTravelledAndCheckRange()) { return; + } - if (!player.isDead() && controllable) - direction = GeneralMethods.getDirection(player.getLocation(), GeneralMethods.getTargetedLocation(player, range, Material.WATER)).normalize(); + updateDirectionIfControllable(); - location = location.add(direction.clone().multiply(1)); - if (RegionProtection.isRegionProtected(this, location)) { - travelled = range; - return; - } - if (GeneralMethods.isSolid(location.getBlock()) || isWater(location.getBlock())) { - travelled = range; + location.add(direction.clone().multiply(1)); + + if (checkEnvironmentCollision()) { return; } - ParticleEffect flame = bPlayer.hasSubElement(Element.BLUE_FIRE) ? ParticleEffect.SOUL_FIRE_FLAME : ParticleEffect.FLAME; - flame.display(location, 5, Math.random(), Math.random(), Math.random(), 0.02); - ParticleEffect.SMOKE_LARGE.display(location, 2, Math.random(), Math.random(), Math.random(), 0.01); - FireAbility.playFirebendingSound(location); + displayAttackParticles(); + playAttackSoundsAndLight(); + placeFire(); + handleEntityCollisions(); + } + } - JCMethods.emitLight(location); + private boolean incrementTravelledAndCheckRange() { + travelled++; + return travelled < range; + } - placeFire(); + private void updateDirectionIfControllable() { + if (!player.isDead() && controllable) { + direction = GeneralMethods.getDirection(player.getLocation(), GeneralMethods.getTargetedLocation(player, range, Material.WATER)).normalize(); + } + } + + private boolean checkEnvironmentCollision() { + if (RegionProtection.isRegionProtected(this, location) || GeneralMethods.isSolid(location.getBlock()) || isWater(location.getBlock())) { + travelled = range; + return true; + } + return false; + } + + private void displayAttackParticles() { + ParticleEffect flame = bPlayer.hasSubElement(Element.BLUE_FIRE) ? ParticleEffect.SOUL_FIRE_FLAME : ParticleEffect.FLAME; + flame.display(location, 5, Math.random(), Math.random(), Math.random(), 0.02); + ParticleEffect.SMOKE_LARGE.display(location, 2, Math.random(), Math.random(), Math.random(), 0.01); + } + + private void playAttackSoundsAndLight() { + FireAbility.playFirebendingSound(location); + JCMethods.emitLight(location); + } - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.5)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand) && !RegionProtection.isRegionProtected(this, entity.getLocation()) && !((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))) { - DamageHandler.damageEntity(entity, damage, this); - entity.setFireTicks(Math.round(burnTime / 50F)); - travelled = range; - } + private void handleEntityCollisions() { + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.5)) { + if (isAttackableEntity(entity)) { + DamageHandler.damageEntity(entity, damage, this); + entity.setFireTicks(Math.round(burnTime / 50F)); + travelled = range; + return; } } } + private boolean isAttackableEntity(Entity entity) { + return entity instanceof LivingEntity && + entity.getEntityId() != player.getEntityId() && + !(entity instanceof ArmorStand) && + !RegionProtection.isRegionProtected(this, entity.getLocation()) && + !((entity instanceof Player targetPlayer) && Commands.invincible.contains((targetPlayer).getName())); + } + private void placeFire() { if (GeneralMethods.isSolid(location.getBlock().getRelative(BlockFace.DOWN))) { location.getBlock().setType(Material.FIRE); diff --git a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESStream.java b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESStream.java index 41b16c7..efc8577 100644 --- a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESStream.java +++ b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESStream.java @@ -13,9 +13,10 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - import com.projectkorra.projectkorra.util.TempFallingBlock; -import org.bukkit.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; import org.bukkit.block.BlockState; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Entity; @@ -25,7 +26,7 @@ import java.util.ArrayList; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; /** * @author jedk1 @@ -33,6 +34,14 @@ */ public class ESStream extends AvatarAbility implements AddonAbility { + private boolean cancelAbility; + private int requiredUses; + private long regen; + private Location stream; + private Location origin; + private Vector dir; + private int angle; + @Attribute(Attribute.COOLDOWN) private long cooldown; @Attribute(Attribute.KNOCKBACK) @@ -41,29 +50,22 @@ public class ESStream extends AvatarAbility implements AddonAbility { private double range; @Attribute(Attribute.DAMAGE) private double damage; - private boolean cancelAbility; - private int requiredUses; - @Attribute(Attribute.RADIUS) private double radius; - private long regen; - - private Location stream; - private Location origin; - private Vector dir; - - private int an; - Random rand = new Random(); public ESStream(Player player) { super(player); + if (!hasAbility(player, ElementSphere.class)) { return; } + ElementSphere currES = getAbility(player, ElementSphere.class); + if (bPlayer.isOnCooldown("ESStream")) { return; } + setFields(); if (currES.getAirUses() < requiredUses @@ -89,9 +91,10 @@ public ESStream(Player player) { stream = player.getEyeLocation(); origin = player.getEyeLocation(); dir = player.getEyeLocation().getDirection(); - an = 0; + angle = 0; start(); + if (!isRemoved()) { bPlayer.addCooldown("ESStream", getCooldown()); } @@ -112,118 +115,163 @@ public void setFields() { @Override public void progress() { - if (player == null || !player.isOnline()) { - remove(); + if (!checkStreamValidity()) { return; } - if (origin.distance(stream) >= range) { - remove(); + if (checkStreamRangeAndProtection()) { return; } - if (RegionProtection.isRegionProtected(player, stream, this)) { - remove(); + handleNearbyEntities(); + + updateStreamDirection(); + + stream.add(dir); + + if (handleBlockCollision()) { return; } + playStreamParticles(); + } + + private boolean checkStreamValidity() { + return player != null && player.isOnline(); + } + + private boolean checkStreamRangeAndProtection() { + if (origin.distance(stream) >= range || RegionProtection.isRegionProtected(player, stream, this)) { + remove(); + return true; + } + return false; + } + + private void handleNearbyEntities() { for (Entity e : GeneralMethods.getEntitiesAroundPoint(stream, 1.5)) { if (e instanceof Player && e == player) { continue; } - GeneralMethods.setVelocity(this, e, dir.normalize().multiply(knockback)); - if (e instanceof LivingEntity) { - DamageHandler.damageEntity(e, damage, this); - } + applyStreamEffects(e); } + } + + private void applyStreamEffects(Entity entity) { + GeneralMethods.setVelocity(this, entity, dir.normalize().multiply(knockback)); + if (entity instanceof LivingEntity) { + DamageHandler.damageEntity(entity, damage, this); + } + } + private void updateStreamDirection() { if (!player.isDead() && hasAbility(player, ElementSphere.class)) { Location loc = stream.clone(); dir = GeneralMethods.getDirection(loc, player.getTargetBlock(null, (int) range).getLocation()).normalize().multiply(1.2); } + } - stream.add(dir); - + private boolean handleBlockCollision() { if (!isTransparent(stream.getBlock())) { - List blocks = new ArrayList<>(); - for (Location loc : GeneralMethods.getCircle(stream, (int) radius, 0, false, true, 0)) { - if (JCMethods.isUnbreakable(loc.getBlock())) continue; - if (RegionProtection.isRegionProtected(this, loc)) continue; - blocks.add(loc.getBlock().getState()); - new RegenTempBlock(loc.getBlock(), Material.AIR, Material.AIR.createBlockData(), regen, false); - } - for (Entity e : GeneralMethods.getEntitiesAroundPoint(stream, radius)) { - if (e instanceof Player && e == player) { - continue; - } - if (RegionProtection.isRegionProtected(this, e.getLocation()) || ((e instanceof Player) && Commands.invincible.contains(((Player) e).getName()))){ - continue; - } - GeneralMethods.setVelocity(this, e, dir.normalize().multiply(knockback)); - if (e instanceof LivingEntity) { - DamageHandler.damageEntity(e, damage, this); - } - } + triggerCollisionEffects(); + remove(); + return true; + } + return false; + } + + private void triggerCollisionEffects() { + ThreadLocalRandom rand = ThreadLocalRandom.current(); + List blocks = getAffectedBlocks(); + damageNearbyEntitiesOnCollision(); + displayCollisionParticles(); + playCollisionSounds(rand); + spawnFallingBlocks(rand, blocks); + } - ParticleEffect.FLAME.display(stream, 20, Math.random(), Math.random(), Math.random(), 0.5); - ParticleEffect.SMOKE_LARGE.display(stream, 20, Math.random(), Math.random(), Math.random(), 0.5); - ParticleEffect.FIREWORKS_SPARK.display(stream, 20, Math.random(), Math.random(), Math.random(), 0.5); - ParticleEffect.SMOKE_LARGE.display(stream, 20, Math.random(), Math.random(), Math.random(), 0.5); - ParticleEffect.EXPLOSION_HUGE.display(stream, 5, Math.random(), Math.random(), Math.random(), 0.5); + private List getAffectedBlocks() { + List blocks = new ArrayList<>(); + for (Location loc : GeneralMethods.getCircle(stream, (int) radius, 0, false, true, 0)) { + if (JCMethods.isUnbreakable(loc.getBlock()) || RegionProtection.isRegionProtected(this, loc)) continue; + blocks.add(loc.getBlock().getState()); + new RegenTempBlock(loc.getBlock(), Material.AIR, Material.AIR.createBlockData(), regen, false); + } + return blocks; + } - stream.getWorld().playSound(stream, (rand.nextBoolean()) ? Sound.ENTITY_FIREWORK_ROCKET_BLAST : Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, 1f, 1f); - stream.getWorld().playSound(stream, (rand.nextBoolean()) ? Sound.ENTITY_FIREWORK_ROCKET_TWINKLE : Sound.ENTITY_FIREWORK_ROCKET_TWINKLE_FAR, 1f, 1f); + private void damageNearbyEntitiesOnCollision() { + GeneralMethods.getEntitiesAroundPoint(stream, radius).stream().filter(e -> !(e instanceof Player) || e != player).filter(e -> !RegionProtection.isRegionProtected(this, e.getLocation()) && (!(e instanceof Player targetPlayer) || !Commands.invincible.contains((targetPlayer).getName()))).forEach(e -> { + GeneralMethods.setVelocity(this, e, dir.normalize().multiply(knockback)); + if (e instanceof LivingEntity) DamageHandler.damageEntity(e, damage, this); + }); + } - for (BlockState block : blocks) { - double x = rand.nextDouble() / 3; - double z = rand.nextDouble() / 3; + private void displayCollisionParticles() { + ParticleEffect.FLAME.display(stream, 20, 0.5F, 0.5F, 0.5F, 0.5F); + ParticleEffect.SMOKE_LARGE.display(stream, 20, 0.5F, 0.5F, 0.5F, 0.5F); + ParticleEffect.FIREWORKS_SPARK.display(stream, 20, 0.5F, 0.5F, 0.5F, 0.5F); + ParticleEffect.SMOKE_LARGE.display(stream, 20, 0.5F, 0.5F, 0.5F, 0.5F); + ParticleEffect.EXPLOSION_HUGE.display(stream, 5, 0.5F, 0.5F, 0.5F, 0.5F); + } - x = (rand.nextBoolean()) ? -x : x; - z = (rand.nextBoolean()) ? -z : z; + private void playCollisionSounds(ThreadLocalRandom rand) { + stream.getWorld().playSound(stream, rand.nextBoolean() ? Sound.ENTITY_FIREWORK_ROCKET_BLAST : Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, 1f, 1f); + stream.getWorld().playSound(stream, rand.nextBoolean() ? Sound.ENTITY_FIREWORK_ROCKET_TWINKLE : Sound.ENTITY_FIREWORK_ROCKET_TWINKLE_FAR, 1f, 1f); + } - new TempFallingBlock(block.getLocation().add(0, 1, 0), block.getBlockData(), dir.clone().add(new Vector(x, 0, z)).normalize().multiply(-1), this); - } - remove(); - return; + private void spawnFallingBlocks(ThreadLocalRandom rand, List blocks) { + for (BlockState block : blocks) { + double x = (rand.nextBoolean() ? -1 : 1) * rand.nextDouble() / 3; + double z = (rand.nextBoolean() ? -1 : 1) * rand.nextDouble() / 3; + new TempFallingBlock(block.getLocation().add(0, 1, 0), block.getBlockData(), dir.clone().add(new Vector(x, 0, z)).normalize().multiply(-1), this); } - - an += 20; - if (an > 360) { - an = 0; + } + + private void playStreamParticles() { + angle += 20; + if (angle > 360) { + angle = 0; } for (int i = 0; i < 4; i++) { - for (double d = -4; d <= 0; d += .1) { - if (origin.distance(stream) < d) { - continue; - } - Location l = stream.clone().add(dir.clone().normalize().multiply(d)); - double r = d * -1 / 5; - if (r > .75) { - r = .75; - } + playIndividualStreamParticles(i); + } + } - Vector ov = GeneralMethods.getOrthogonalVector(dir, an + (90 * i) + d, r); - Location pl = l.clone().add(ov.clone()); - switch (i) { - case 0: - ParticleEffect flame = bPlayer.hasSubElement(Element.BLUE_FIRE) ? ParticleEffect.SOUL_FIRE_FLAME : ParticleEffect.FLAME; - flame.display(pl, 1, 0.05F, 0.05F, 0.05F, 0.005F); - break; - case 1: - if (rand.nextInt(30) == 0) { - JCMethods.displayColoredParticles("#FFFFFF", pl, 1, 0, 0, 0, 0.003f); - } else { - JCMethods.displayColoredParticles("#FFFFFF", pl, 1, 0.05, 0.05, 0.05, 0.005f, 50); - } - break; - case 2: - GeneralMethods.displayColoredParticle("06C1FF", pl); - break; - case 3: - GeneralMethods.displayColoredParticle("754719", pl); - break; + private void playIndividualStreamParticles(int particleIndex) { + for (double d = -4; d <= 0; d += 0.1) { + if (origin.distance(stream) < d) continue; + Location l = stream.clone().add(dir.clone().normalize().multiply(d)); + double r = Math.min(0.75, d * -1 / 5); + Vector ov = GeneralMethods.getOrthogonalVector(dir, angle + (90 * particleIndex) + d, r); + Location pl = l.clone().add(ov.clone()); + displayStreamParticle(pl, particleIndex); + } + } + + private void displayStreamParticle(Location location, int index) { + ThreadLocalRandom rand = ThreadLocalRandom.current(); + switch (index) { + case 0: + ParticleEffect flame = bPlayer.hasSubElement(Element.BLUE_FIRE) ? ParticleEffect.SOUL_FIRE_FLAME : ParticleEffect.FLAME; + flame.display(location, 1, 0.05F, 0.05F, 0.05F, 0.005F); + break; + case 1: + String color = "#FFFFFF"; + float offset = 0.05F; + float speed = 0.005F; + int viewDistance = 50; + if (rand.nextInt(30) == 0) { + JCMethods.displayColoredParticles(color, location, 1, 0, 0, 0, speed); + } else { + JCMethods.displayColoredParticles(color, location, 1, offset, offset, offset, speed, viewDistance); } - } + break; + case 2: + GeneralMethods.displayColoredParticle("06C1FF", location); + break; + case 3: + GeneralMethods.displayColoredParticle("754719", location); + break; } } diff --git a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESWater.java b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESWater.java index 76e92e0..4d0fbb3 100644 --- a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESWater.java +++ b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ESWater.java @@ -12,7 +12,6 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.Levelled; @@ -40,19 +39,26 @@ public class ESWater extends AvatarAbility implements AddonAbility { public ESWater(Player player) { super(player); + if (!hasAbility(player, ElementSphere.class)) { return; } + ElementSphere currES = getAbility(player, ElementSphere.class); if (currES.getWaterUses() == 0) { return; } + if (bPlayer.isOnCooldown("ESWater")) { return; } + setFields(); + location = player.getEyeLocation().clone().add(player.getEyeLocation().getDirection().multiply(1)); + start(); + if (!isRemoved()) { bPlayer.addCooldown("ESWater", getCooldown()); currES.setWaterUses(currES.getWaterUses() - 1); @@ -74,44 +80,82 @@ public void progress() { remove(); return; } + if (travelled >= range) { remove(); return; } + advanceAttack(); } - private void advanceAttack() { - for (int i = 0; i < speed; i++) { - travelled++; - if (travelled >= range) - return; - - if (!player.isDead()) - direction = GeneralMethods.getDirection(player.getLocation(), GeneralMethods.getTargetedLocation(player, range, Material.WATER)).normalize(); - location = location.add(direction.clone().multiply(1)); - if (RegionProtection.isRegionProtected(this, location)){ - travelled = range; - return; - } - if (GeneralMethods.isSolid(location.getBlock()) || !isTransparent(location.getBlock())) { - travelled = range; - return; - } - - WaterAbility.playWaterbendingSound(location); - if (isWater(location.getBlock())) - ParticleEffect.WATER_BUBBLE.display(location, 3, 0.5, 0.5, 0.5); - new RegenTempBlock(location.getBlock(), Material.WATER, Material.WATER.createBlockData(bd -> ((Levelled) bd).setLevel(0)), 100L); - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.5)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand) && !RegionProtection.isRegionProtected(this, entity.getLocation()) && !((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))) { - DamageHandler.damageEntity(entity, damage, this); - travelled = range; - } - } - } - } + private void advanceAttack() { + for (int i = 0; i < speed; i++) { + if (!incrementTravelledAndCheckRange()) { + return; + } + + updateDirection(); + + location.add(direction.clone().multiply(1)); + + if (checkCollision()) { + return; + } + + playAttackEffects(); + handleBlockTransformation(); + handleEntityCollisions(); + } + } + + private boolean incrementTravelledAndCheckRange() { + travelled++; + return travelled < range; + } + + private void updateDirection() { + if (!player.isDead()) { + direction = GeneralMethods.getDirection(player.getLocation(), GeneralMethods.getTargetedLocation(player, range, Material.WATER)).normalize(); + } + } + + private boolean checkCollision() { + if (RegionProtection.isRegionProtected(this, location) || GeneralMethods.isSolid(location.getBlock()) || !isTransparent(location.getBlock())) { + travelled = range; + return true; + } + return false; + } + + private void playAttackEffects() { + WaterAbility.playWaterbendingSound(location); + if (isWater(location.getBlock())) { + ParticleEffect.WATER_BUBBLE.display(location, 3, 0.5, 0.5, 0.5); + } + } + + private void handleBlockTransformation() { + new RegenTempBlock(location.getBlock(), Material.WATER, Material.WATER.createBlockData(bd -> ((Levelled) bd).setLevel(0)), 100L); + } + + private void handleEntityCollisions() { + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.5)) { + if (isAttackableEntity(entity)) { + DamageHandler.damageEntity(entity, damage, this); + travelled = range; + return; + } + } + } + + private boolean isAttackableEntity(Entity entity) { + return entity instanceof LivingEntity && + entity.getEntityId() != player.getEntityId() && + !(entity instanceof ArmorStand) && + !RegionProtection.isRegionProtected(this, entity.getLocation()) && + !((entity instanceof Player targetPlayer) && Commands.invincible.contains((targetPlayer).getName())); + } @Override public long getCooldown() { diff --git a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ElementSphere.java b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ElementSphere.java index 51e78de..22e9122 100644 --- a/src/com/jedk1/jedcore/ability/avatar/elementsphere/ElementSphere.java +++ b/src/com/jedk1/jedcore/ability/avatar/elementsphere/ElementSphere.java @@ -13,7 +13,6 @@ import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.ParticleEffect; - import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -27,399 +26,495 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.Random; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ThreadLocalRandom; public class ElementSphere extends AvatarAbility implements AddonAbility, MultiAbility { - public static ConcurrentHashMap> abilities = new ConcurrentHashMap>(); - - private World world; - - public int airUses; - public int fireUses; - public int waterUses; - public int earthUses; - - @Attribute(Attribute.COOLDOWN) - public long cooldown; - @Attribute(Attribute.DURATION) - public long duration; - @Attribute(Attribute.HEIGHT) - private double height; - @Attribute(Attribute.SPEED) - private double speed; - - private boolean setup; - private Location location; - private double yaw; - private int point; - private long endTime; - - private long lastClickTime; - - private static final ArrayList multiAbilityInfo = new ArrayList<>(); - - static { - multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.AIR)); - multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.EARTH)); - multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.FIRE)); - multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.WATER)); - multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.AVATAR)); - } - - Random rand = new Random(); - - public ElementSphere(Player player) { - super(player); - ElementSphere oldES = getAbility(player, ElementSphere.class); - if (oldES != null) { - if (player.isSneaking()) { - oldES.prepareCancel(); - } else { - if (oldES.setup) { - if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { - return; - } - - switch (player.getInventory().getHeldItemSlot()) { - case 0: - if (player.hasPermission("bending.ability.ElementSphere.Air")) { - new ESAir(player); - } - break; - case 1: - if (player.hasPermission("bending.ability.ElementSphere.Earth")) { - new ESEarth(player); - } - break; - case 2: - if (player.hasPermission("bending.ability.ElementSphere.Fire")) { - new ESFire(player); - } - break; - case 3: - if (player.hasPermission("bending.ability.ElementSphere.Water")) { - new ESWater(player); - } - break; - case 4: - if (player.hasPermission("bending.ability.ElementSphere.Stream")) { - new ESStream(player); - } - break; - default: - break; - } - } - } - return; - } - - setFields(); - location = player.getLocation().clone().subtract(0, 1, 0); - - if (bPlayer.canBend(this)) { - world = player.getWorld(); - endTime = System.currentTimeMillis() + duration; - start(); - if (!isRemoved()) { - MultiAbilityManager.bindMultiAbility(player, "ElementSphere"); - bPlayer.addCooldown(this); - flightHandler.createInstance(player, this.getName()); - if (ChatColor.stripColor(bPlayer.getBoundAbilityName()) == null) { - remove(); - } - } - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - airUses = config.getInt("Abilities.Avatar.ElementSphere.Air.Uses"); - fireUses = config.getInt("Abilities.Avatar.ElementSphere.Fire.Uses"); - waterUses = config.getInt("Abilities.Avatar.ElementSphere.Water.Uses"); - earthUses = config.getInt("Abilities.Avatar.ElementSphere.Earth.Uses"); - cooldown = config.getLong("Abilities.Avatar.ElementSphere.Cooldown"); - duration = config.getLong("Abilities.Avatar.ElementSphere.Duration"); - height = config.getDouble("Abilities.Avatar.ElementSphere.MaxControlledHeight"); - speed = config.getDouble("Abilities.Avatar.ElementSphere.FlySpeed"); - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline() || world != player.getWorld()) { - remove(); - return; - } - if (player.getGameMode().equals(GameMode.SPECTATOR)) { - remove(); - return; - } - if (!bPlayer.isToggled()) { - remove(); - return; - } - if (!MultiAbilityManager.hasMultiAbilityBound(player, "ElementSphere")) { - remove(); - return; - } - if (System.currentTimeMillis() > endTime && duration > 0) { - remove(); - return; - } - if (airUses == 0 && fireUses == 0 && waterUses == 0 && earthUses == 0) { - remove(); - return; - } - player.setFallDistance(0); - if (player.isSneaking()) - player.setVelocity(player.getLocation().getDirection().multiply(speed)); - - Block block = getGround(); - if (block != null) { - double dy = player.getLocation().getY() - block.getY(); - if (dy > height) { - removeFlight(); - } else { - allowFlight(); - } - } - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.5)) { - if (!RegionProtection.isRegionProtected(player, entity.getLocation(), this)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand)) { - entity.setVelocity(entity.getLocation().toVector().subtract(player.getLocation().toVector()).multiply(1)); - } - } - } - - location = player.getLocation().clone().subtract(0, 1, 0); - playParticles(); - setup = true; - } - - private void allowFlight() { - if (!player.getAllowFlight()) { - player.setAllowFlight(true); - } - if (!player.isFlying()) { - player.setFlying(true); - } - } - - private void removeFlight() { - if (player.getAllowFlight()) { - player.setAllowFlight(false); - } - if (player.isFlying()) { - player.setFlying(false); - } - } - - private Block getGround() { - Block standingblock = player.getLocation().getBlock(); - for (int i = 0; i <= height + 5; i++) { - Block block = standingblock.getRelative(BlockFace.DOWN, i); - if (GeneralMethods.isSolid(block) || block.isLiquid()) { - return block; - } - } - return null; - } - - private void playParticles() { - Location fakeLoc = location.clone(); - fakeLoc.setPitch(0); - fakeLoc.setYaw((float) (yaw += 40)); - Vector direction = fakeLoc.getDirection(); - if (airUses != 0) - for (double j = -180; j <= 180; j += 45) { - Location tempLoc = fakeLoc.clone(); - Vector newDir = direction.clone().multiply(2 * Math.cos(Math.toRadians(j))); - tempLoc.add(newDir); - tempLoc.setY(tempLoc.getY() + 2 + (2 * Math.sin(Math.toRadians(j)))); - if (rand.nextInt(30) == 0) { - JCMethods.displayColoredParticles("#FFFFFF", tempLoc, 1, 0, 0, 0, 0.003f); - } else { - JCMethods.displayColoredParticles("#FFFFFF", tempLoc, 1, 0, 0, 0, 0.003f, 50); - } - } - - point++; - if (fireUses != 0) - for (int i = -180; i < 180; i += 40) { - double angle = (i * Math.PI / 180); - double x = 2 * Math.cos(angle + point); - double z = 2 * Math.sin(angle + point); - Location loc = location.clone(); - loc.add(x, 2, z); - ParticleEffect flame = bPlayer.hasSubElement(Element.BLUE_FIRE) ? ParticleEffect.SOUL_FIRE_FLAME : ParticleEffect.FLAME; - flame.display(loc, 0, 0, 0, 0, 1); - JCMethods.emitLight(loc); - } - - point++; - Location location = this.location.clone().add(0, 2, 0); - for (int i = -180; i < 180; i += 30) { - double angle = (i * Math.PI / 180); - double xRotation = 3.141592653589793D / 3 * 2.1; - Vector v = new Vector(Math.cos(angle + point), Math.sin(angle + point), 0.0D).multiply(2); - Vector v1 = v.clone(); - rotateAroundAxisX(v, xRotation); - rotateAroundAxisY(v, -((location.getYaw() * Math.PI / 180) - 1.575)); - rotateAroundAxisX(v1, -xRotation); - rotateAroundAxisY(v1, -((location.getYaw() * Math.PI / 180) - 1.575)); - - if (waterUses != 0) - GeneralMethods.displayColoredParticle("06C1FF", location.clone().add(v)); - - if (earthUses != 0) - GeneralMethods.displayColoredParticle("754719", location.clone().add(v1)); - } - - if (point == 360) - point = 0; - } - - private void rotateAroundAxisX(Vector v, double angle) { - double cos = Math.cos(angle); - double sin = Math.sin(angle); - double y = v.getY() * cos - v.getZ() * sin; - double z = v.getY() * sin + v.getZ() * cos; - v.setY(y).setZ(z); - } - - private void rotateAroundAxisY(Vector v, double angle) { - double cos = Math.cos(angle); - double sin = Math.sin(angle); - double x = v.getX() * cos + v.getZ() * sin; - double z = v.getX() * -sin + v.getZ() * cos; - v.setX(x).setZ(z); - } - - @Override - public void remove() { - super.remove(); - MultiAbilityManager.unbindMultiAbility(player); - flightHandler.removeInstance(player, this.getName()); - } - - public void prepareCancel() { - if (System.currentTimeMillis() < lastClickTime + 500L) { - remove(); - } else { - lastClickTime = System.currentTimeMillis(); - } - } - - public int getAirUses() { - return airUses; - } - - public void setAirUses(int airuses) { - this.airUses = airuses; - } - - public int getEarthUses() { - return earthUses; - } - - public void setEarthUses(int earthuses) { - this.earthUses = earthuses; - } - - public int getFireUses() { - return fireUses; - } - - public void setFireUses(int fireuses) { - this.fireUses = fireuses; - } - - public int getWaterUses() { - return waterUses; - } - - public void setWaterUses(int wateruses) { - this.waterUses = wateruses; - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public boolean requireAvatar() { - return false; - } - - @Override - public String getName() { - return "ElementSphere"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Avatar.ElementSphere.Description"); - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Avatar.ElementSphere.Enabled"); - } - - @Override - public ArrayList getMultiAbilities() { - FileConfiguration lang = getLanguageConfig(); - - String airName = lang.getString("Abilities.Avatar.ElementSphereAir.Name"); - String fireName = lang.getString("Abilities.Avatar.ElementSphereFire.Name"); - String waterName = lang.getString("Abilities.Avatar.ElementSphereWater.Name"); - String earthName = lang.getString("Abilities.Avatar.ElementSphereEarth.Name"); - String streamName = lang.getString("Abilities.Avatar.ElementSphereStream.Name"); - - multiAbilityInfo.get(0).setName(airName); - multiAbilityInfo.get(1).setName(earthName); - multiAbilityInfo.get(2).setName(fireName); - multiAbilityInfo.get(3).setName(waterName); - multiAbilityInfo.get(4).setName(streamName); - - return multiAbilityInfo; - } -} + protected static final ConcurrentMap> abilities = new ConcurrentHashMap<>(); + private static final ArrayList multiAbilityInfo = new ArrayList<>(); + + static { + multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.AIR)); + multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.EARTH)); + multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.FIRE)); + multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.WATER)); + multiAbilityInfo.add(new MultiAbilityInfoSub("", Element.AVATAR)); + } + + private World world; + private int airUses; + private int fireUses; + private int waterUses; + private int earthUses; + private boolean setup; + private Location location; + private double yaw; + private int point; + private long endTime; + private long lastClickTime; + + @Attribute(Attribute.COOLDOWN) + public long cooldown; + @Attribute(Attribute.DURATION) + public long duration; + @Attribute(Attribute.HEIGHT) + private double height; + @Attribute(Attribute.SPEED) + private double speed; + + public ElementSphere(Player player) { + super(player); + + ElementSphere oldES = getAbility(player, ElementSphere.class); + + if (handleExistingSphere(player, oldES)) { + return; + } + + if (canStartNewSphere()) { + initializeNewSphere(player); + } + } + + private boolean handleExistingSphere(Player player, ElementSphere oldES) { + if (oldES != null) { + if (player.isSneaking()) { + oldES.prepareCancel(); + } else { + if (oldES.setup) { + handleElementSwitch(player); + } + } + return true; + } + return false; + } + + private void handleElementSwitch(Player player) { + if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { + return; + } + + switch (player.getInventory().getHeldItemSlot()) { + case 0: + if (checkPermission(player, "Air")) new ESAir(player); + break; + case 1: + if (checkPermission(player, "Earth")) new ESEarth(player); + break; + case 2: + if (checkPermission(player, "Fire")) new ESFire(player); + break; + case 3: + if (checkPermission(player, "Water")) new ESWater(player); + break; + case 4: + if (checkPermission(player, "Stream")) new ESStream(player); + break; + } + } + + private boolean checkPermission(Player player, String element) { + return player.hasPermission("bending.ability.ElementSphere." + element); + } + + private boolean canStartNewSphere() { + return bPlayer.canBend(this); + } + + private void initializeNewSphere(Player player) { + setFields(); + location = player.getLocation().clone().subtract(0, 1, 0); + world = player.getWorld(); + endTime = System.currentTimeMillis() + duration; + start(); + + if (!isRemoved()) { + bindAndCooldown(player); + enableFlight(player); + checkBoundAbilityName(); + } + } + + private void bindAndCooldown(Player player) { + MultiAbilityManager.bindMultiAbility(player, "ElementSphere"); + bPlayer.addCooldown(this); + } + + private void enableFlight(Player player) { + flightHandler.createInstance(player, this.getName()); + } + + private void checkBoundAbilityName() { + if (ChatColor.stripColor(bPlayer.getBoundAbilityName()) == null) { + remove(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + airUses = config.getInt("Abilities.Avatar.ElementSphere.Air.Uses"); + fireUses = config.getInt("Abilities.Avatar.ElementSphere.Fire.Uses"); + waterUses = config.getInt("Abilities.Avatar.ElementSphere.Water.Uses"); + earthUses = config.getInt("Abilities.Avatar.ElementSphere.Earth.Uses"); + cooldown = config.getLong("Abilities.Avatar.ElementSphere.Cooldown"); + duration = config.getLong("Abilities.Avatar.ElementSphere.Duration"); + height = config.getDouble("Abilities.Avatar.ElementSphere.MaxControlledHeight"); + speed = config.getDouble("Abilities.Avatar.ElementSphere.FlySpeed"); + } + + @Override + public void progress() { + if (!checkPlayerValidity()) { + return; + } + + if (!checkAbilityPrerequisites()) { + return; + } + + if (isDurationOver()) { + remove(); + return; + } + + if (!hasUsableElements()) { + remove(); + return; + } + + handlePlayerMovement(); + handleFlight(); + handleEntityPush(); + updateLocationAndPlayParticles(); + + setup = true; + } + + private boolean checkPlayerValidity() { + return !player.isDead() && player.isOnline() && world == player.getWorld() && !player.getGameMode().equals(GameMode.SPECTATOR); + } + + private boolean checkAbilityPrerequisites() { + return bPlayer.isToggled() && MultiAbilityManager.hasMultiAbilityBound(player, "ElementSphere"); + } + + private boolean isDurationOver() { + return duration > 0 && System.currentTimeMillis() > endTime; + } + + private boolean hasUsableElements() { + return airUses > 0 || fireUses > 0 || waterUses > 0 || earthUses > 0; + } + + private void handlePlayerMovement() { + player.setFallDistance(0); + if (player.isSneaking()) { + player.setVelocity(player.getLocation().getDirection().multiply(speed)); + } + } + + private void handleFlight() { + Block block = getGround(); + if (block != null) { + double dy = player.getLocation().getY() - block.getY(); + if (dy > height) { + removeFlight(); + } else { + allowFlight(); + } + } + } + + private void handleEntityPush() { + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.5)) { + if (isPushableEntity(entity)) { + entity.setVelocity(entity.getLocation().toVector().subtract(player.getLocation().toVector()).multiply(1)); + } + } + } + + private boolean isPushableEntity(Entity entity) { + return entity instanceof LivingEntity && + entity.getEntityId() != player.getEntityId() && + !(entity instanceof ArmorStand) && + !RegionProtection.isRegionProtected(player, entity.getLocation(), this); + } + + private void updateLocationAndPlayParticles() { + location = player.getLocation().clone().subtract(0, 1, 0); + playParticles(); + } + + private void allowFlight() { + if (!player.getAllowFlight()) { + player.setAllowFlight(true); + } + if (!player.isFlying()) { + player.setFlying(true); + } + } + + private void removeFlight() { + if (player.getAllowFlight()) { + player.setAllowFlight(false); + } + if (player.isFlying()) { + player.setFlying(false); + } + } + + private Block getGround() { + Block standingblock = player.getLocation().getBlock(); + + for (int i = 0; i <= height + 5; i++) { + Block block = standingblock.getRelative(BlockFace.DOWN, i); + if (GeneralMethods.isSolid(block) || block.isLiquid()) { + return block; + } + } + + return null; + } + + private void playParticles() { + playAirParticles(); + playFireParticles(); + playWaterEarthParticles(); + updatePointCounter(); + } + + private void playAirParticles() { + if (airUses != 0) { + double currentYaw = yaw + 40; + yaw = currentYaw; + Location fakeLoc = createRotatedLocation(location.clone(), 0, currentYaw); + Vector direction = fakeLoc.getDirection(); + for (double j = -180; j <= 180; j += 45) { + Location tempLoc = calculateAirParticleLocation(fakeLoc, direction, j); + displayAirParticle(tempLoc); + } + } + } + + private Location createRotatedLocation(Location baseLoc, double pitchOffset, double yawOffset) { + Location newLoc = baseLoc.clone(); + newLoc.setPitch((float) pitchOffset); + newLoc.setYaw((float) yawOffset); + return newLoc; + } + + private Location calculateAirParticleLocation(Location center, Vector direction, double angleDegrees) { + Location tempLoc = center.clone(); + double angleRadians = Math.toRadians(angleDegrees); + Vector newDir = direction.clone().multiply(2 * Math.cos(angleRadians)); + tempLoc.add(newDir); + tempLoc.setY(tempLoc.getY() + 2 + (2 * Math.sin(angleRadians))); + return tempLoc; + } + + private void displayAirParticle(Location loc) { + String color = "#FFFFFF"; + int count = 1; + float offsetX = 0; + float offsetY = 0; + float offsetZ = 0; + float particleSpeed = 0.003f; + int viewDistance = 50; + + if (ThreadLocalRandom.current().nextInt(30) == 0) { + JCMethods.displayColoredParticles(color, loc, count, offsetX, offsetY, offsetZ, particleSpeed); + } else { + JCMethods.displayColoredParticles(color, loc, count, offsetX, offsetY, offsetZ, particleSpeed, viewDistance); + } + } + + private void playFireParticles() { + if (fireUses != 0) { + ParticleEffect flame = bPlayer.hasSubElement(Element.BLUE_FIRE) ? ParticleEffect.SOUL_FIRE_FLAME : ParticleEffect.FLAME; + for (int i = -180; i < 180; i += 40) { + Location particleLoc = calculateCircularLocation(location, 2, i, 2); + flame.display(particleLoc, 0, 0, 0, 0, 1); + JCMethods.emitLight(particleLoc); + } + } + } + + private Location calculateCircularLocation(Location center, double radius, double angleOffsetDegrees, double yOffset) { + double angleRadians = Math.toRadians(angleOffsetDegrees); + double x = radius * Math.cos(angleRadians + point); + double z = radius * Math.sin(angleRadians + point); + return center.clone().add(x, yOffset, z); + } + + private void playWaterEarthParticles() { + Location centerLoc = location.clone().add(0, 2, 0); + double xRotation = Math.PI * 2.1 / 3; + double yawRadians = -(centerLoc.getYaw() * Math.PI / 180 - 1.575); + + for (int i = -180; i < 180; i += 30) { + double angle = Math.toRadians(i); + Vector v = new Vector(Math.cos(angle + point), Math.sin(angle + point), 0.0D).multiply(2); + Vector v1 = v.clone(); + + rotateAroundAxisX(v, xRotation); + rotateAroundAxisY(v, yawRadians); + rotateAroundAxisX(v1, -xRotation); + rotateAroundAxisY(v1, yawRadians); + if (waterUses != 0) { + centerLoc.getWorld().spawnParticle(Particle.WATER_WAKE, centerLoc.clone().add(v), 3, 0.0, 0.0, 0.0, 0.005F); + GeneralMethods.displayColoredParticle("06C1FF", centerLoc.clone().add(v)); + } + if (earthUses != 0) { + GeneralMethods.displayColoredParticle("754719", centerLoc.clone().add(v1)); + } + } + } + + private void updatePointCounter() { + point = (point + 1) % 360; + } + + private void rotateAroundAxisX(Vector v, double angle) { + double cos = Math.cos(angle); + double sin = Math.sin(angle); + double y = v.getY() * cos - v.getZ() * sin; + double z = v.getY() * sin + v.getZ() * cos; + v.setY(y).setZ(z); + } + + private void rotateAroundAxisY(Vector v, double angle) { + double cos = Math.cos(angle); + double sin = Math.sin(angle); + double x = v.getX() * cos + v.getZ() * sin; + double z = v.getX() * -sin + v.getZ() * cos; + v.setX(x).setZ(z); + } + + @Override + public void remove() { + super.remove(); + MultiAbilityManager.unbindMultiAbility(player); + flightHandler.removeInstance(player, this.getName()); + } + + public void prepareCancel() { + if (System.currentTimeMillis() < lastClickTime + 500L) { + remove(); + } else { + lastClickTime = System.currentTimeMillis(); + } + } + + public int getAirUses() { + return airUses; + } + + public void setAirUses(int airuses) { + this.airUses = airuses; + } + + public int getEarthUses() { + return earthUses; + } + + public void setEarthUses(int earthuses) { + this.earthUses = earthuses; + } + + public int getFireUses() { + return fireUses; + } + + public void setFireUses(int fireuses) { + this.fireUses = fireuses; + } + + public int getWaterUses() { + return waterUses; + } + + public void setWaterUses(int wateruses) { + this.waterUses = wateruses; + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public boolean requireAvatar() { + return false; + } + + @Override + public String getName() { + return "ElementSphere"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Avatar.ElementSphere.Description"); + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Avatar.ElementSphere.Enabled"); + } + + @Override + public ArrayList getMultiAbilities() { + FileConfiguration lang = getLanguageConfig(); + + String airName = lang.getString("Abilities.Avatar.ElementSphereAir.Name"); + String fireName = lang.getString("Abilities.Avatar.ElementSphereFire.Name"); + String waterName = lang.getString("Abilities.Avatar.ElementSphereWater.Name"); + String earthName = lang.getString("Abilities.Avatar.ElementSphereEarth.Name"); + String streamName = lang.getString("Abilities.Avatar.ElementSphereStream.Name"); + + multiAbilityInfo.get(0).setName(airName); + multiAbilityInfo.get(1).setName(earthName); + multiAbilityInfo.get(2).setName(fireName); + multiAbilityInfo.get(3).setName(waterName); + multiAbilityInfo.get(4).setName(streamName); + + return multiAbilityInfo; + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/chiblocking/Backstab.java b/src/com/jedk1/jedcore/ability/chiblocking/Backstab.java index f6c87ec..701121a 100644 --- a/src/com/jedk1/jedcore/ability/chiblocking/Backstab.java +++ b/src/com/jedk1/jedcore/ability/chiblocking/Backstab.java @@ -1,18 +1,17 @@ package com.jedk1.jedcore.ability.chiblocking; +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; +import com.projectkorra.projectkorra.BendingPlayer; +import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.ChiAbility; import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.chiblocking.passive.ChiPassive; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; - -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.BendingPlayer; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.ChiAbility; -import com.projectkorra.projectkorra.chiblocking.passive.ChiPassive; import org.bukkit.util.Vector; public class Backstab extends ChiAbility implements AddonAbility { diff --git a/src/com/jedk1/jedcore/ability/chiblocking/DaggerThrow.java b/src/com/jedk1/jedcore/ability/chiblocking/DaggerThrow.java index 0d94826..1b57acf 100644 --- a/src/com/jedk1/jedcore/ability/chiblocking/DaggerThrow.java +++ b/src/com/jedk1/jedcore/ability/chiblocking/DaggerThrow.java @@ -4,6 +4,7 @@ import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.util.AbilitySelector; +import com.jedk1.jedcore.util.ThreadUtil; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.ChiAbility; @@ -12,7 +13,6 @@ import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; @@ -28,350 +28,324 @@ import java.util.stream.Collectors; public class DaggerThrow extends ChiAbility implements AddonAbility { - private static final List INTERACTIONS = new ArrayList<>(); - private static boolean particles; - private static double damage; - - private long endTime; - private int shots = 1; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - private boolean limitEnabled; - @Attribute("MaxShots") - private int maxShots; - private int hits = 0; - private final List arrows = new ArrayList<>(); - - public DaggerThrow(Player player) { - super(player); - - if (this instanceof DamageAbility) { - return; - } - - if (!bPlayer.canBend(this)) { - return; - } - - if (bPlayer.isOnCooldown("DaggerThrowShot")) { - return; - } - - if (hasAbility(player, DaggerThrow.class)) { - DaggerThrow dt = getAbility(player, DaggerThrow.class); - dt.shootArrow(); - return; - } - - setFields(); - - start(); - if (!isRemoved()) { - shootArrow(); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Chi.DaggerThrow.Cooldown"); - limitEnabled = config.getBoolean("Abilities.Chi.DaggerThrow.MaxDaggers.Enabled"); - maxShots = config.getInt("Abilities.Chi.DaggerThrow.MaxDaggers.Amount"); - particles = config.getBoolean("Abilities.Chi.DaggerThrow.ParticleTrail"); - damage = config.getDouble("Abilities.Chi.DaggerThrow.Damage"); - - loadInteractions(); - } - - private void loadInteractions() { - INTERACTIONS.clear(); - - String path = "Abilities.Chi.DaggerThrow.Interactions"; - - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - ConfigurationSection section = config.getConfigurationSection(path); - for (String abilityName : section.getKeys(false)) { - INTERACTIONS.add(new AbilityInteraction(abilityName)); - } - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - if (System.currentTimeMillis() > endTime) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (shots > maxShots && limitEnabled) { - bPlayer.addCooldown(this); - remove(); - } - } - - private void shootArrow() { - if (JCMethods.removeItemFromInventory(player, Material.ARROW, 1)) { - shots++; - Location location = player.getEyeLocation(); - - Vector vector = location.toVector(). - add(location.getDirection().multiply(2.5)). - toLocation(location.getWorld()).toVector(). - subtract(player.getEyeLocation().toVector()); - - Arrow arrow = player.launchProjectile(Arrow.class); - arrow.setVelocity(vector); - arrow.getLocation().setDirection(vector); - arrow.setKnockbackStrength(0); - arrow.setBounce(false); - arrow.setMetadata("daggerthrow", new FixedMetadataValue(JedCore.plugin, "1")); - - if (particles) { - arrow.setCritical(true); - } - - arrows.add(arrow); - endTime = System.currentTimeMillis() + 500; - bPlayer.addCooldown("DaggerThrowShot", 100); - } - } - - public static void damageEntityFromArrow(LivingEntity entity, Arrow arrow) { - if (RegionProtection.isRegionProtected((Player) arrow.getShooter(), arrow.getLocation(), "DaggerThrow")) { - return; - } - - arrow.setVelocity(new Vector(0, 0, 0)); - entity.setNoDamageTicks(0); - double prevHealth = entity.getHealth(); - Player shooter = (Player) arrow.getShooter(); - DamageAbility da = new DamageAbility(shooter); - DamageHandler.damageEntity(entity, damage, da); - da.remove(); - if (prevHealth > entity.getHealth()) { - arrow.remove(); - } - - if (!(entity instanceof Player)) { - return; - } - - DaggerThrow dt = CoreAbility.getAbility(shooter, DaggerThrow.class); - if (dt == null) { - return; - } - - ++dt.hits; - - Player target = (Player)entity; - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(target); - - for (AbilityInteraction interaction : INTERACTIONS) { - if (!interaction.enabled) continue; - if (dt.hits < interaction.hitRequirement) continue; - - CoreAbility abilityDefinition = AbilitySelector.getAbility(interaction.name); - if (abilityDefinition == null) continue; - - CoreAbility ability = CoreAbility.getAbility(target, abilityDefinition.getClass()); - if (ability == null) continue; - - ability.remove(); - bPlayer.addCooldown(ability, interaction.cooldown); - } - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public List getLocations() { - return arrows.stream().map(Arrow::getLocation).collect(Collectors.toList()); - } - - @Override - public double getCollisionRadius() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getDouble("Abilities.Chi.DaggerThrow.AbilityCollisionRadius"); - } - - @Override - public void handleCollision(Collision collision) { - if (collision.isRemovingFirst()) { - Location location = collision.getLocationFirst(); - - Optional collidedObject = arrows.stream().filter(arrow -> arrow.getLocation().equals(location)).findAny(); - - if (collidedObject.isPresent()) { - arrows.remove(collidedObject.get()); - collidedObject.get().remove(); - } - } - } - - @Override - public String getName() { - return "DaggerThrow"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return false; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Chi.DaggerThrow.Description"); - } - - public static boolean hasParticleTrail() { - return particles; - } - - public static double getDamage() { - return damage; - } - - public long getEndTime() { - return endTime; - } - - public void setEndTime(long endTime) { - this.endTime = endTime; - } - - public int getShots() { - return shots; - } - - public void setShots(int shots) { - this.shots = shots; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public boolean isLimitEnabled() { - return limitEnabled; - } - - public void setLimitEnabled(boolean limitEnabled) { - this.limitEnabled = limitEnabled; - } - - public int getMaxShots() { - return maxShots; - } - - public void setMaxShots(int maxShots) { - this.maxShots = maxShots; - } - - public int getHits() { - return hits; - } - - public void setHits(int hits) { - this.hits = hits; - } - - public List getArrows() { - return arrows; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Chi.DaggerThrow.Enabled"); - } - - public static class DamageAbility extends DaggerThrow { - - public DamageAbility(Player player) { - super(player); - start(); - } - - @Override - public long getCooldown() { - return 0; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "DaggerThrow"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return false; - } - - @Override - public void progress() { - remove(); - } - } - - private class AbilityInteraction { - public boolean enabled; - public long cooldown; - public int hitRequirement; - public String name; - - public AbilityInteraction(String abilityName) { - this.name = abilityName; - loadConfig(); - } - - public void loadConfig() { - ConfigurationSection config = JedCoreConfig.getConfig(player); - this.enabled = config.getBoolean("Abilities.Chi.DaggerThrow.Interactions." + name + ".Enabled", true); - this.cooldown = config.getLong("Abilities.Chi.DaggerThrow.Interactions." + name + ".Cooldown", 1000); - this.hitRequirement = config.getInt("Abilities.Chi.DaggerThrow.Interactions." + name + ".HitsRequired", 1); - } - } -} + private static final List INTERACTIONS = new ArrayList<>(); + + private final List arrows = new ArrayList<>(); + + private boolean limitEnabled; + private boolean requireArrows; + private boolean allowPickup; + private boolean particles; + private long endTime; + private int shots = 1; + private int hits = 0; + + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute("MaxShots") + private int maxShots; + + public DaggerThrow(Player player) { + super(player); + + if (!bPlayer.canBend(this)) { + return; + } + + if (bPlayer.isOnCooldown("DaggerThrowShot")) { + return; + } + + if (hasAbility(player, DaggerThrow.class)) { + DaggerThrow dt = getAbility(player, DaggerThrow.class); + dt.shootArrow(); + return; + } + + setFields(); + + start(); + + if (!isRemoved()) { + shootArrow(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Chi.DaggerThrow.Cooldown"); + limitEnabled = config.getBoolean("Abilities.Chi.DaggerThrow.MaxDaggers.Enabled"); + maxShots = config.getInt("Abilities.Chi.DaggerThrow.MaxDaggers.Amount"); + particles = config.getBoolean("Abilities.Chi.DaggerThrow.ParticleTrail"); + damage = config.getDouble("Abilities.Chi.DaggerThrow.Damage"); + requireArrows = config.getBoolean("Abilities.Chi.DaggerThrow.RequireArrows"); + allowPickup = config.getBoolean("Abilities.Chi.DaggerThrow.AllowPickup"); + + loadInteractions(); + } + + private void loadInteractions() { + INTERACTIONS.clear(); + + String path = "Abilities.Chi.DaggerThrow.Interactions"; + + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + ConfigurationSection section = config.getConfigurationSection(path); + + for (String abilityName : section.getKeys(false)) { + INTERACTIONS.add(new AbilityInteraction(abilityName)); + } + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + + if (System.currentTimeMillis() > endTime) { + bPlayer.addCooldown(this); + remove(); + return; + } + + if (shots > maxShots && limitEnabled) { + bPlayer.addCooldown(this); + remove(); + } + } + + private void shootArrow() { + shots++; + Location location = player.getEyeLocation(); + + Vector vector = location.toVector(). + add(location.getDirection().multiply(2.5)). + toLocation(location.getWorld()).toVector(). + subtract(player.getEyeLocation().toVector()); + + if (requireArrows) JCMethods.removeItemFromInventory(player, Material.ARROW, 1); + + Arrow arrow = player.launchProjectile(Arrow.class); + arrow.setVelocity(vector); + arrow.getLocation().setDirection(vector); + arrow.setKnockbackStrength(0); + arrow.setBounce(false); + arrow.setMetadata("daggerthrow", new FixedMetadataValue(JedCore.plugin, "1")); + + if (!allowPickup) arrow.setPickupStatus(Arrow.PickupStatus.DISALLOWED); + + if (particles) { + arrow.setCritical(true); + } + + arrows.add(arrow); + endTime = System.currentTimeMillis() + 500; + bPlayer.addCooldown("DaggerThrowShot", 100); + } + + public void damageEntityFromArrow(LivingEntity entity, Arrow arrow) { + if (!(arrow.getShooter() instanceof Player shooter)) return; + + if (RegionProtection.isRegionProtected(shooter, arrow.getLocation(), "DaggerThrow")) return; + + ThreadUtil.ensureEntity(arrow, () -> arrow.setVelocity(new Vector(0, 0, 0))); + ThreadUtil.ensureEntity(entity, () -> entity.setNoDamageTicks(0)); + + double prevHealth = entity.getHealth(); + + ThreadUtil.ensureEntity(entity, () -> DamageHandler.damageEntity(entity, damage, this)); + + if (prevHealth > entity.getHealth()) { + ThreadUtil.ensureEntity(arrow, arrow::remove); + } + + if (!(entity instanceof Player target)) { + return; + } + + DaggerThrow daggerThrow = CoreAbility.getAbility(shooter, DaggerThrow.class); + if (daggerThrow == null) { + return; + } + + daggerThrow.hits++; + BendingPlayer targetBPlayer = BendingPlayer.getBendingPlayer(target); + + for (AbilityInteraction interaction : INTERACTIONS) { + if (!interaction.enabled || daggerThrow.hits < interaction.hitRequirement) { + continue; + } + + CoreAbility abilityDefinition = AbilitySelector.getAbility(interaction.name); + if (abilityDefinition == null) { + continue; + } + + CoreAbility ability = CoreAbility.getAbility(target, abilityDefinition.getClass()); + if (ability == null) { + continue; + } + + ability.remove(); + targetBPlayer.addCooldown(ability, interaction.cooldown); + } + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public List getLocations() { + return arrows.stream().map(Arrow::getLocation).collect(Collectors.toList()); + } + + @Override + public double getCollisionRadius() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getDouble("Abilities.Chi.DaggerThrow.AbilityCollisionRadius"); + } + + @Override + public void handleCollision(Collision collision) { + if (collision.isRemovingFirst()) { + Location location = collision.getLocationFirst(); + + Optional collidedObject = arrows.stream().filter(arrow -> arrow.getLocation().equals(location)).findAny(); + + if (collidedObject.isPresent()) { + arrows.remove(collidedObject.get()); + collidedObject.get().remove(); + } + } + } + + @Override + public String getName() { + return "DaggerThrow"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return false; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Chi.DaggerThrow.Description"); + } + + public boolean hasParticleTrail() { + return particles; + } + + public double getDamage() { + return damage; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } + + public int getShots() { + return shots; + } + + public void setShots(int shots) { + this.shots = shots; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public boolean isLimitEnabled() { + return limitEnabled; + } + + public void setLimitEnabled(boolean limitEnabled) { + this.limitEnabled = limitEnabled; + } + + public int getMaxShots() { + return maxShots; + } + + public void setMaxShots(int maxShots) { + this.maxShots = maxShots; + } + + public int getHits() { + return hits; + } + + public void setHits(int hits) { + this.hits = hits; + } + + public List getArrows() { + return arrows; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Chi.DaggerThrow.Enabled"); + } + + private class AbilityInteraction { + public boolean enabled; + public long cooldown; + public int hitRequirement; + public String name; + + public AbilityInteraction(String abilityName) { + this.name = abilityName; + loadConfig(); + } + + public void loadConfig() { + ConfigurationSection config = JedCoreConfig.getConfig(player); + this.enabled = config.getBoolean("Abilities.Chi.DaggerThrow.Interactions." + name + ".Enabled", true); + this.cooldown = config.getLong("Abilities.Chi.DaggerThrow.Interactions." + name + ".Cooldown", 1000); + this.hitRequirement = config.getInt("Abilities.Chi.DaggerThrow.Interactions." + name + ".HitsRequired", 1); + } + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/EarthKick.java b/src/com/jedk1/jedcore/ability/earthbending/EarthKick.java index 505e17b..31b9e9a 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/EarthKick.java +++ b/src/com/jedk1/jedcore/ability/earthbending/EarthKick.java @@ -8,13 +8,14 @@ import com.jedk1.jedcore.util.BlockUtil; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.EarthAbility; -import com.projectkorra.projectkorra.ability.ElementalAbility; import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.attribute.Attribute; +import com.projectkorra.projectkorra.earthbending.passive.DensityShift; import com.projectkorra.projectkorra.region.RegionProtection; -import com.projectkorra.projectkorra.util.*; - -import org.bukkit.Bukkit; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.TempBlock; +import com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -24,291 +25,319 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.UUID; +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; import static java.util.stream.Collectors.toList; public class EarthKick extends EarthAbility implements AddonAbility { - private final List temps = new ArrayList<>(); - - private BlockData materialData; - private Location location; - private final Random rand = new Random(); - - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute("MaxShots") - private int earthBlocks; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute("CollisionRadius") - private double entityCollisionRadius; - private Block block; - - private boolean multipleHits; - private int sourceRange; - private int spread; - private double velocity; - - private Set hitEntities = new HashSet<>(); - - public EarthKick(Player player) { - super(player); - - if (!bPlayer.canBend(this)) { - return; - } - - setFields(); - location = player.getLocation(); - if ((player.getLocation().getPitch() > -5) && prepare()) { - if (RegionProtection.isRegionProtected(this, block.getLocation())) { - return; - } - launchBlocks(); - start(); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Earth.EarthKick.Cooldown"); - earthBlocks = config.getInt("Abilities.Earth.EarthKick.EarthBlocks"); - damage = config.getDouble("Abilities.Earth.EarthKick.Damage"); - entityCollisionRadius = config.getDouble("Abilities.Earth.EarthKick.EntityCollisionRadius"); - - multipleHits = config.getBoolean("Abilities.Earth.EarthKick.MultipleHits"); - sourceRange = config.getInt("Abilities.Earth.EarthKick.SourceRange"); - spread = config.getInt("Abilities.Earth.EarthKick.Spread"); - velocity = config.getDouble("Abilities.Earth.EarthKick.Velocity"); - - if (entityCollisionRadius < 1.0) { - entityCollisionRadius = 1.0; - } - } - - private boolean prepare() { - block = player.getTargetBlock(getTransparentMaterialSet(), sourceRange); - if (!isEarthbendable(player, block)){ - return false; - } - - if (block != null && !isMetal(block)) { - materialData = block.getBlockData().clone(); - location.setX(block.getX() + 0.5); - location.setY(block.getY()); - location.setZ(block.getZ() + 0.5); - - return true; - } - - return false; - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - - if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { - remove(); - return; - } - - bPlayer.addCooldown(this); - track(); - - if (temps.isEmpty()) { - remove(); - } - } - - private void launchBlocks() { - if (getMovedEarth().containsKey(block)) { - block.setType(Material.AIR); - } - if (block.getType() != Material.AIR) { - TempBlock air = new TempBlock(block, Material.AIR); - air.setRevertTime(5000L); - } - - location.setPitch(0); - location.add(location.getDirection()); - - if (!isAir(location.getBlock().getType())) { - location.setY(location.getY() + 1.0); - } - - ParticleEffect.CRIT.display(location, 10, Math.random(), Math.random(), Math.random(), 0.1); - - int yaw = Math.round(location.getYaw()); - - playEarthbendingSound(location); - - for (int i = 0; i < earthBlocks; i++) { - location.setYaw(yaw + rand.nextInt((spread * 2) + 1) - spread); - location.setPitch(rand.nextInt(25) - 45); - - Vector v = location.clone().add(0, 0.8, 0).getDirection().normalize(); - Location location1 = location.clone().add(new Vector(v.getX() * 2, v.getY(), v.getZ() * 2)); - Vector dir = location1.setDirection(location.getDirection()).getDirection().multiply(velocity); - - temps.add(new TempFallingBlock(location, materialData, dir, this)); - } - } - - public void track() { - List destroy = new ArrayList<>(); - - for (TempFallingBlock tfb : temps) { - FallingBlock fb = tfb.getFallingBlock(); - - if (fb == null || fb.isDead()) { - destroy.add(tfb); - continue; - } - - for (int i = 0; i < 2; i++) { - ParticleEffect.BLOCK_CRACK.display(fb.getLocation(), 1, 0.0, 0.0, 0.0, 0.1, materialData); - ParticleEffect.BLOCK_CRACK.display(fb.getLocation(), 1, 0.0, 0.0, 0.0, 0.2, materialData); - } - - AABB collider = BlockUtil.getFallingBlockBoundsFull(fb).scale(entityCollisionRadius * 2.0); - - CollisionDetector.checkEntityCollisions(player, collider, (entity) -> { - UUID uuid = entity.getUniqueId(); - if (this.multipleHits || hitEntities.add(uuid)) { - DamageHandler.damageEntity(entity, damage, this); - } - return false; - }); - } - - temps.removeAll(destroy); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public List getLocations() { - return temps.stream().map(TempFallingBlock::getLocation).collect(toList()); - } - - @Override - public double getCollisionRadius() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getDouble("Abilities.Earth.EarthKick.AbilityCollisionRadius"); - } - - @Override - public void handleCollision(Collision collision) { - CollisionUtil.handleFallingBlockCollisions(collision, temps); - } - - @Override - public String getName() { - return "EarthKick"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthKick.Description"); - } - - public List getTemps() { - return temps; - } - - public BlockData getMaterialData() { - return materialData; - } - - public void setMaterialData(BlockData materialData) { - this.materialData = materialData; - } - - public void setLocation(Location location) { - this.location = location; - } - - public int getEarthBlocksQuantity() { - return earthBlocks; - } - - public void setEarthBlocksQuantity(int earthBlocks) { - this.earthBlocks = earthBlocks; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public double getEntityCollisionRadius() { - return entityCollisionRadius; - } - - public void setEntityCollisionRadius(double entityCollisionRadius) { - this.entityCollisionRadius = entityCollisionRadius; - } - - public Block getBlock() { - return block; - } - - public void setBlock(Block block) { - this.block = block; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.EarthKick.Enabled"); - } -} + private final List temps = new ArrayList<>(); + private final Set hitEntities = new HashSet<>(); + + private BlockData materialData; + private Location location; + private Block block; + private boolean multipleHits; + private int sourceRange; + private int spread; + private double velocity; + private boolean allowMetal; + private boolean replaceSource; + + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute("MaxShots") + private int earthBlocks; + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute(Attribute.DAMAGE) + private double metalDmg; + @Attribute("CollisionRadius") + private double entityCollisionRadius; + + public EarthKick(Player player) { + super(player); + + if (!bPlayer.canBend(this)) { + return; + } + + setFields(); + + location = player.getLocation(); + + if ((player.getLocation().getPitch() > -5) && prepare()) { + if (RegionProtection.isRegionProtected(this, block.getLocation())) { + return; + } + launchBlocks(); + start(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Earth.EarthKick.Cooldown"); + earthBlocks = config.getInt("Abilities.Earth.EarthKick.EarthBlocks"); + damage = config.getDouble("Abilities.Earth.EarthKick.Damage.Normal"); + metalDmg = config.getDouble("Abilities.Earth.EarthKick.Damage.Metal"); + entityCollisionRadius = config.getDouble("Abilities.Earth.EarthKick.EntityCollisionRadius"); + multipleHits = config.getBoolean("Abilities.Earth.EarthKick.MultipleHits"); + sourceRange = config.getInt("Abilities.Earth.EarthKick.SourceRange"); + spread = config.getInt("Abilities.Earth.EarthKick.Spread"); + velocity = config.getDouble("Abilities.Earth.EarthKick.Velocity"); + allowMetal = config.getBoolean("Abilities.Earth.EarthKick.AllowMetal"); + replaceSource = config.getBoolean("Abilities.Earth.EarthKick.ReplaceSource"); + + if (entityCollisionRadius < 1.0) { + entityCollisionRadius = 1.0; + } + } + + private boolean prepare() { + block = player.getTargetBlock(getTransparentMaterialSet(), sourceRange); + + if (EarthAbility.getMovedEarth().containsKey(block)) { + return false; + } + + if (!isEarthbendable(player, block)) { + return false; + } + + if (TempBlock.isTempBlock(block)) { + TempBlock.get(block).revertBlock(); + } + + if (DensityShift.isPassiveSand(block)) { + DensityShift.revertSand(block); + } + + if (block != null && (allowMetal || !isMetal(block))) { + materialData = block.getBlockData().clone(); + location.setX(block.getX() + 0.5); + location.setY(block.getY()); + location.setZ(block.getZ() + 0.5); + + return true; + } + + return false; + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + + if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { + remove(); + return; + } + + bPlayer.addCooldown(this); + + track(); + + if (temps.isEmpty()) { + remove(); + } + } + + private void launchBlocks() { + if (replaceSource) { + if (getMovedEarth().containsKey(block)) { + block.setType(Material.AIR); + } + + if (block.getType() != Material.AIR) { + TempBlock air = new TempBlock(block, Material.AIR); + air.setRevertTime(5000L); + } + } + + location.setPitch(0); + location.add(location.getDirection()); + + if (!isAir(location.getBlock().getType())) { + location.setY(location.getY() + 1.0); + } + + ParticleEffect.CRIT.display(location, 10, Math.random(), Math.random(), Math.random(), 0.1); + + int yaw = Math.round(location.getYaw()); + + playEarthbendingSound(location); + + ThreadLocalRandom rand = ThreadLocalRandom.current(); + + for (int i = 0; i < earthBlocks; i++) { + location.setYaw(yaw + rand.nextInt((spread * 2) + 1) - spread); + location.setPitch(rand.nextInt(25) - 45); + + Vector v = location.clone().add(0, 0.8, 0).getDirection().normalize(); + Location location1 = location.clone().add(new Vector(v.getX() * 2, v.getY(), v.getZ() * 2)); + Vector dir = location1.setDirection(location.getDirection()).getDirection().multiply(velocity); + + temps.add(new TempFallingBlock(location, materialData, dir, this)); + } + } + + public void track() { + List destroy = new ArrayList<>(); + + for (TempFallingBlock tfb : temps) { + FallingBlock fb = tfb.getFallingBlock(); + + if (fb == null || fb.isDead()) { + destroy.add(tfb); + continue; + } + + for (int i = 0; i < 2; i++) { + ParticleEffect.BLOCK_CRACK.display(fb.getLocation(), 1, 0.0, 0.0, 0.0, 0.1, materialData); + ParticleEffect.BLOCK_CRACK.display(fb.getLocation(), 1, 0.0, 0.0, 0.0, 0.2, materialData); + } + + AABB collider = BlockUtil.getFallingBlockBoundsFull(fb).scale(entityCollisionRadius * 2.0); + + CollisionDetector.checkEntityCollisions(player, collider, (entity) -> { + UUID uuid = entity.getUniqueId(); + if (this.multipleHits || hitEntities.add(uuid)) { + DamageHandler.damageEntity(entity, isMetal(fb.getBlockData().getMaterial()) ? metalDmg : damage, this); + } + return false; + }); + } + + temps.removeAll(destroy); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public List getLocations() { + return temps.stream().map(TempFallingBlock::getLocation).collect(toList()); + } + + @Override + public double getCollisionRadius() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getDouble("Abilities.Earth.EarthKick.AbilityCollisionRadius"); + } + + @Override + public void handleCollision(Collision collision) { + CollisionUtil.handleFallingBlockCollisions(collision, temps); + } + + @Override + public String getName() { + return "EarthKick"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthKick.Description"); + } + + public List getTemps() { + return temps; + } + + public BlockData getMaterialData() { + return materialData; + } + + public void setMaterialData(BlockData materialData) { + this.materialData = materialData; + } + + public void setLocation(Location location) { + this.location = location; + } + + public int getEarthBlocksQuantity() { + return earthBlocks; + } + + public void setEarthBlocksQuantity(int earthBlocks) { + this.earthBlocks = earthBlocks; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public double getMetalDmg() { + return metalDmg; + } + + public void setMetalDmg(double metalDmg) { + this.metalDmg = metalDmg; + } + + public double getEntityCollisionRadius() { + return entityCollisionRadius; + } + + public void setEntityCollisionRadius(double entityCollisionRadius) { + this.entityCollisionRadius = entityCollisionRadius; + } + + public Block getBlock() { + return block; + } + + public void setBlock(Block block) { + this.block = block; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.EarthKick.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/EarthLine.java b/src/com/jedk1/jedcore/ability/earthbending/EarthLine.java index 90e0ba4..e047ed3 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/EarthLine.java +++ b/src/com/jedk1/jedcore/ability/earthbending/EarthLine.java @@ -3,9 +3,6 @@ import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.policies.removal.*; -import com.jedk1.jedcore.util.RegenTempBlock; - -import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.EarthAbility; @@ -13,12 +10,9 @@ import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.earthbending.passive.DensityShift; import com.projectkorra.projectkorra.region.RegionProtection; -import com.projectkorra.projectkorra.util.BlockSource; -import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.DamageHandler; - +import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.util.TempFallingBlock; - import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Material; @@ -32,79 +26,84 @@ public class EarthLine extends EarthAbility implements AddonAbility { - private Location location; - private Location endLocation; - private Block sourceBlock; - private Material sourceType; - private boolean progressing; - private boolean hitted; - private int goOnAfterHit; - private long removalTime = -1; - - private long useCooldown; - private long prepareCooldown; - @Attribute(Attribute.DURATION) - private long maxDuration; - @Attribute(Attribute.RANGE) - private double range; - @Attribute(Attribute.SELECT_RANGE) - private double prepareRange; - private double sourceKeepRange; - @Attribute(Attribute.RADIUS) - private int affectingRadius; - @Attribute(Attribute.DAMAGE) - private double damage; - private boolean allowChangeDirection; - private CompositeRemovalPolicy removalPolicy; - - public EarthLine(Player player) { - super(player); - - if (!isEnabled()) return; - - if (!bPlayer.canBend(this)) { - return; - } - goOnAfterHit = 1; - - setFields(); - if (prepare()) { - start(); - if (!isRemoved() && prepareCooldown != 0) { - bPlayer.addCooldown(this, prepareCooldown); - } - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - this.removalPolicy = new CompositeRemovalPolicy(this, - new CannotBendRemovalPolicy(this.bPlayer, this, true, true), - new IsOfflineRemovalPolicy(this.player), - new IsDeadRemovalPolicy(this.player), - new SwappedSlotsRemovalPolicy<>(bPlayer, EarthLine.class) - ); - - this.removalPolicy.load(config); - - useCooldown = config.getLong("Abilities.Earth.EarthLine.Cooldown"); - prepareCooldown = config.getLong("Abilities.Earth.EarthLine.PrepareCooldown"); - range = config.getInt("Abilities.Earth.EarthLine.Range"); - prepareRange = config.getDouble("Abilities.Earth.EarthLine.PrepareRange"); - sourceKeepRange = config.getDouble("Abilities.Earth.EarthLine.SourceKeepRange"); - affectingRadius = config.getInt("Abilities.Earth.EarthLine.AffectingRadius"); - damage = config.getDouble("Abilities.Earth.EarthLine.Damage"); - allowChangeDirection = config.getBoolean("Abilities.Earth.EarthLine.AllowChangeDirection"); - maxDuration = config.getLong("Abilities.Earth.EarthLine.MaxDuration"); - } + private Location location; + private Location endLocation; + private Block sourceBlock; + private TempBlock sourceTempBlock; + private Material sourceType; + private boolean progressing; + private boolean hitted; + private int goOnAfterHit; + private long removalTime = -1; + private boolean allowChangeDirection; + private CompositeRemovalPolicy removalPolicy; + private long useCooldown; + private long prepareCooldown; + private double sourceKeepRange; + + @Attribute(Attribute.DURATION) + private long maxDuration; + @Attribute(Attribute.RANGE) + private double range; + @Attribute(Attribute.SELECT_RANGE) + private double prepareRange; + @Attribute(Attribute.RADIUS) + private int affectingRadius; + @Attribute(Attribute.DAMAGE) + private double damage; + + public EarthLine(Player player) { + super(player); + + if (!isEnabled()) return; + + if (!bPlayer.canBend(this)) { + return; + } + goOnAfterHit = 1; + + setFields(); + + if (prepare()) { + start(); + if (!isRemoved() && prepareCooldown != 0) { + bPlayer.addCooldown(this, prepareCooldown); + } + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + this.removalPolicy = new CompositeRemovalPolicy(this, + new CannotBendRemovalPolicy(this.bPlayer, this, true, true), + new IsOfflineRemovalPolicy(this.player), + new IsDeadRemovalPolicy(this.player), + new SwappedSlotsRemovalPolicy<>(bPlayer, EarthLine.class) + ); + + this.removalPolicy.load(config); + + useCooldown = config.getLong("Abilities.Earth.EarthLine.Cooldown"); + prepareCooldown = config.getLong("Abilities.Earth.EarthLine.PrepareCooldown"); + range = config.getInt("Abilities.Earth.EarthLine.Range"); + prepareRange = config.getDouble("Abilities.Earth.EarthLine.PrepareRange"); + sourceKeepRange = config.getDouble("Abilities.Earth.EarthLine.SourceKeepRange"); + affectingRadius = config.getInt("Abilities.Earth.EarthLine.AffectingRadius"); + damage = config.getDouble("Abilities.Earth.EarthLine.Damage"); + allowChangeDirection = config.getBoolean("Abilities.Earth.EarthLine.AllowChangeDirection"); + maxDuration = config.getLong("Abilities.Earth.EarthLine.MaxDuration"); + } public boolean prepare() { - final Block block = BlockSource.getEarthSourceBlock(this.player, this.range, ClickType.SHIFT_DOWN); + final Block block = getEarthSourceBlock(this.range); + if (block == null || !this.isEarthbendable(block)) { return false; } else if (TempBlock.isTempBlock(block) && !EarthAbility.isBendableEarthTempBlock(block)) { return false; + } else if (EarthAbility.getMovedEarth().containsKey(block)) { + return false; } boolean selectedABlockInUse = false; @@ -126,364 +125,366 @@ public boolean prepare() { this.sourceBlock = block; this.focusBlock(); + + return true; + } + + private void focusBlock() { + if (DensityShift.isPassiveSand(this.sourceBlock)) { + DensityShift.revertSand(this.sourceBlock); + } + + if (this.sourceBlock.getType() == Material.SAND) { + this.sourceType = Material.SAND; + sourceTempBlock = new TempBlock(sourceBlock, Material.SANDSTONE.createBlockData()); + } else if (this.sourceBlock.getType() == Material.RED_SAND) { + this.sourceType = Material.RED_SAND; + sourceTempBlock = new TempBlock(sourceBlock, Material.RED_SANDSTONE.createBlockData()); + } else if (this.sourceBlock.getType() == Material.STONE) { + this.sourceType = Material.STONE; + sourceTempBlock = new TempBlock(sourceBlock, Material.COBBLESTONE.createBlockData()); + } else { + this.sourceType = this.sourceBlock.getType(); + sourceTempBlock = new TempBlock(sourceBlock, Material.STONE.createBlockData()); + } + + this.location = this.sourceBlock.getLocation(); + } + + private void unfocusBlock() { + sourceTempBlock.revertBlock(); + } + + @Override + public void remove() { + sourceTempBlock.revertBlock(); + super.remove(); + } + + // todo: static + private static Location getTargetLocation(Player player) { + ConfigurationSection config = JedCoreConfig.getConfig(player); + + double range = config.getInt("Abilities.Earth.EarthLine.Range"); + + Entity target = GeneralMethods.getTargetedEntity(player, range, player.getNearbyEntities(range, range, range)); + Location location; + + if (target == null) { + location = GeneralMethods.getTargetedLocation(player, range); + } else { + location = ((LivingEntity) target).getEyeLocation(); + } + + return location; + } + + public void shootLine(Location endLocation) { + if (useCooldown != 0 && bPlayer.getCooldown(this.getName()) < useCooldown) bPlayer.addCooldown(this, useCooldown); + if (maxDuration > 0) removalTime = System.currentTimeMillis() + maxDuration; + this.endLocation = endLocation; + progressing = true; + sourceBlock.getWorld().playEffect(sourceBlock.getLocation(), Effect.GHAST_SHOOT, 0, 10); + } + + public static void shootLine(Player player) { + if (hasAbility(player, EarthLine.class)) { + EarthLine el = getAbility(player, EarthLine.class); + if (!el.progressing) { + el.shootLine(getTargetLocation(player)); + } + } + } + + private boolean sourceOutOfRange() { + return sourceBlock == null || sourceBlock.getLocation().add(0.5, 0.5, 0.5).distanceSquared(player.getLocation()) > sourceKeepRange * sourceKeepRange || sourceBlock.getWorld() != player.getWorld(); + } + + public void progress() { + if (!progressing) { + if (sourceOutOfRange()) { + unfocusBlock(); + remove(); + } + return; + } + + if (removalPolicy.shouldRemove()) { + remove(); + return; + } + + if (sourceBlock == null || RegionProtection.isRegionProtected(this, location)) { + remove(); + return; + } + + if (removalTime > -1 && System.currentTimeMillis() > removalTime) { + remove(); + return; + } + + if (sourceOutOfRange()) { + remove(); + return; + } + + if (RegionProtection.isRegionProtected(player, location, this)) { + remove(); + return; + } + + if (allowChangeDirection && player.isSneaking() && bPlayer.getBoundAbilityName().equalsIgnoreCase("EarthLine")) { + endLocation = getTargetLocation(player); + } + + double x1 = endLocation.getX(); + double z1 = endLocation.getZ(); + double x0 = sourceBlock.getX(); + double z0 = sourceBlock.getZ(); + + Vector looking = new Vector(x1 - x0, 0.0D, z1 - z0); + Vector push = new Vector(x1 - x0, 0.34999999999999998D, z1 - z0); + + if (location.distance(sourceBlock.getLocation()) < range) { + Material cloneType = location.getBlock().getType(); + Location locationYUP = location.getBlock().getLocation().clone().add(0.5, 0.1, 0.5); + + playEarthbendingSound(location); + + if (isEarthbendable(location.getBlock())) { + new TempBlock(location.getBlock(), Material.AIR.createBlockData(), 700L); + new TempFallingBlock(locationYUP, cloneType.createBlockData(), new Vector(0.0, 0.35, 0.0), this); + } + + location.add(looking.normalize()); + + if (!climb()) { + remove(); + return; + } + + if (hitted) { + if (goOnAfterHit != 0) { + goOnAfterHit--; + } else { + remove(); + return; + } + } else { + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, affectingRadius)) { + if (RegionProtection.isRegionProtected(this, entity.getLocation()) || ((entity instanceof Player) && Commands.invincible.contains(entity.getName()))) { + return; + } + + if ((entity instanceof LivingEntity) && entity.getEntityId() != player.getEntityId()) { + GeneralMethods.setVelocity(this, entity, push.normalize().multiply(2)); + DamageHandler.damageEntity(entity, damage, this); + hitted = true; + } + } + } + } else { + remove(); + return; + } + + if (!isEarthbendable(player, location.getBlock()) && !isTransparent(location.getBlock())) { + remove(); + } + } + + private boolean climb() { + Block above = location.getBlock().getRelative(BlockFace.UP); + + if (!isTransparent(above)) { + // Attempt to climb since the current location has a block above it. + location.add(0, 1, 0); + above = location.getBlock().getRelative(BlockFace.UP); + + // The new location must be earthbendable and have something transparent above it. + return isEarthbendable(location.getBlock()) && isTransparent(above); + } else if (isTransparent(location.getBlock()) ) { + // Attempt to fall since the current location is transparent and the above block was transparent. + location.add(0, -1, 0); + + // The new location must be earthbendable and we already know the block above it is transparent. + return isEarthbendable(location.getBlock()); + } + return true; } - private void focusBlock() { - if (DensityShift.isPassiveSand(this.sourceBlock)) { - DensityShift.revertSand(this.sourceBlock); - } - if (this.sourceBlock.getType() == Material.SAND) { - this.sourceType = Material.SAND; - this.sourceBlock.setType(Material.SANDSTONE); - } else if (this.sourceBlock.getType() == Material.RED_SAND) { - this.sourceType = Material.RED_SAND; - this.sourceBlock.setType(Material.RED_SANDSTONE); - } else if (this.sourceBlock.getType() == Material.STONE) { - this.sourceBlock.setType(Material.COBBLESTONE); - this.sourceType = Material.STONE; - } else { - this.sourceType = this.sourceBlock.getType(); - this.sourceBlock.setType(Material.STONE); - } - - this.location = this.sourceBlock.getLocation(); - } - - private void unfocusBlock() { - sourceBlock.setType(sourceType); - } - - private void breakSourceBlock() { - sourceBlock.setType(sourceType); - new RegenTempBlock(sourceBlock, Material.AIR, Material.AIR.createBlockData(), 5000L); - } - - @Override - public void remove() { - if (sourceBlock != null && sourceBlock.getType() != Material.AIR) { - sourceBlock.setType(sourceType); // Ensure no duplication of the source block - } - super.remove(); - } - - private static Location getTargetLocation(Player player) { - ConfigurationSection config = JedCoreConfig.getConfig(player); - double range = config.getInt("Abilities.Earth.EarthLine.Range"); - Entity target = GeneralMethods.getTargetedEntity(player, range, player.getNearbyEntities(range, range, range)); - Location location; - if (target == null) { - location = GeneralMethods.getTargetedLocation(player, range); - } else { - location = ((LivingEntity) target).getEyeLocation(); - } - return location; - } - - public void shootLine(Location endLocation) { - if (useCooldown != 0 && bPlayer.getCooldown(this.getName()) < useCooldown) bPlayer.addCooldown(this, useCooldown); - if (maxDuration > 0) removalTime = System.currentTimeMillis() + maxDuration; - this.endLocation = endLocation; - progressing = true; - breakSourceBlock(); - sourceBlock.getWorld().playEffect(sourceBlock.getLocation(), Effect.GHAST_SHOOT, 0, 10); - } - - public static void shootLine(Player player) { - if (hasAbility(player, EarthLine.class)) { - EarthLine el = getAbility(player, EarthLine.class); - if (!el.progressing) { - el.shootLine(getTargetLocation(player)); - } - } - } - - private boolean sourceOutOfRange() { - return sourceBlock == null || sourceBlock.getLocation().add(0.5, 0.5, 0.5).distanceSquared(player.getLocation()) > sourceKeepRange * sourceKeepRange || sourceBlock.getWorld() != player.getWorld(); - } - - public void progress() { - if (!progressing) { - if (sourceOutOfRange()) { - unfocusBlock(); - remove(); - } - return; - } - - if (removalPolicy.shouldRemove()) { - remove(); - return; - } - - if (sourceBlock == null || RegionProtection.isRegionProtected(this, location)) { - remove(); - return; - } - - if (removalTime > -1 && System.currentTimeMillis() > removalTime) { - remove(); - return; - } - - if (sourceOutOfRange()) { - remove(); - return; - } - - if (RegionProtection.isRegionProtected(player, location, this)) { - remove(); - return; - } - - if (allowChangeDirection && player.isSneaking() && bPlayer.getBoundAbilityName().equalsIgnoreCase("EarthLine")) { - endLocation = getTargetLocation(player); - } - - double x1 = endLocation.getX(); - double z1 = endLocation.getZ(); - double x0 = sourceBlock.getX(); - double z0 = sourceBlock.getZ(); - Vector looking = new Vector(x1 - x0, 0.0D, z1 - z0); - Vector push = new Vector(x1 - x0, 0.34999999999999998D, z1 - z0); - if (location.distance(sourceBlock.getLocation()) < range) { - Material cloneType = location.getBlock().getType(); - Location locationYUP = location.getBlock().getLocation().clone().add(0.5, 0.1, 0.5); - - playEarthbendingSound(location); - - if (isEarthbendable(location.getBlock())) { - new RegenTempBlock(location.getBlock(), Material.AIR, Material.AIR.createBlockData(), 700L); - new TempFallingBlock(locationYUP, cloneType.createBlockData(), new Vector(0.0, 0.35, 0.0), this); - } - - location.add(looking.normalize()); - - if (!climb()) { - remove(); - return; - } - - if (hitted) { - if (goOnAfterHit != 0) { - goOnAfterHit--; - } else { - remove(); - return; - } - } else { - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, affectingRadius)) { - if (RegionProtection.isRegionProtected(this, entity.getLocation()) || ((entity instanceof Player) && Commands.invincible.contains(entity.getName()))){ - return; - } - if ((entity instanceof LivingEntity) && entity.getEntityId() != player.getEntityId()) { - GeneralMethods.setVelocity(this, entity, push.normalize().multiply(2)); - DamageHandler.damageEntity(entity, damage, this); - hitted = true; - } - } - } - } else { - remove(); - return; - } - - if (!isEarthbendable(player, location.getBlock()) && !isTransparent(location.getBlock())) { - remove(); - } - } - - private boolean climb() { - Block above = location.getBlock().getRelative(BlockFace.UP); - - if (!isTransparent(above)) { - // Attempt to climb since the current location has a block above it. - location.add(0, 1, 0); - above = location.getBlock().getRelative(BlockFace.UP); - - // The new location must be earthbendable and have something transparent above it. - return isEarthbendable(location.getBlock()) && isTransparent(above); - } else if (isTransparent(location.getBlock()) ) { - // Attempt to fall since the current location is transparent and the above block was transparent. - location.add(0, -1, 0); - - // The new location must be earthbendable and we already know the block above it is transparent. - return isEarthbendable(location.getBlock()); - } - - return true; - } - - @Override - public long getCooldown() { - return useCooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public String getName() { - return "EarthLine"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthLine.Description"); - } - - public Location getEndLocation() { - return endLocation; - } - - public void setEndLocation(Location endLocation) { - this.endLocation = endLocation; - } - - public Block getSourceBlock() { - return sourceBlock; - } - - public void setSourceBlock(Block sourceBlock) { - this.sourceBlock = sourceBlock; - } - - public Material getSourceType() { - return sourceType; - } - - public void setSourceType(Material sourceType) { - this.sourceType = sourceType; - } - - public boolean isProgressing() { - return progressing; - } - - public void setProgressing(boolean progressing) { - this.progressing = progressing; - } - - public int getGoOnAfterHit() { - return goOnAfterHit; - } - - public void setGoOnAfterHit(int goOnAfterHit) { - this.goOnAfterHit = goOnAfterHit; - } - - public long getRemovalTime() { - return removalTime; - } - - public void setRemovalTime(long removalTime) { - this.removalTime = removalTime; - } - - public long getUseCooldown() { - return useCooldown; - } - - public void setUseCooldown(long useCooldown) { - this.useCooldown = useCooldown; - } - - public long getPrepareCooldown() { - return prepareCooldown; - } - - public void setPrepareCooldown(long prepareCooldown) { - this.prepareCooldown = prepareCooldown; - } - - public long getMaxDuration() { - return maxDuration; - } - - public void setMaxDuration(long maxDuration) { - this.maxDuration = maxDuration; - } - - public double getRange() { - return range; - } - - public void setRange(double range) { - this.range = range; - } - - public double getPrepareRange() { - return prepareRange; - } - - public void setPrepareRange(double prepareRange) { - this.prepareRange = prepareRange; - } - - public double getSourceKeepRange() { - return sourceKeepRange; - } - - public void setSourceKeepRange(double sourceKeepRange) { - this.sourceKeepRange = sourceKeepRange; - } - - public int getAffectingRadius() { - return affectingRadius; - } + @Override + public long getCooldown() { + return useCooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getName() { + return "EarthLine"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthLine.Description"); + } + + public Location getEndLocation() { + return endLocation; + } + + public void setEndLocation(Location endLocation) { + this.endLocation = endLocation; + } + + public Block getSourceBlock() { + return sourceBlock; + } + + public void setSourceBlock(Block sourceBlock) { + this.sourceBlock = sourceBlock; + } + + public Material getSourceType() { + return sourceType; + } + + public void setSourceType(Material sourceType) { + this.sourceType = sourceType; + } + + public boolean isProgressing() { + return progressing; + } + + public void setProgressing(boolean progressing) { + this.progressing = progressing; + } + + public int getGoOnAfterHit() { + return goOnAfterHit; + } + + public void setGoOnAfterHit(int goOnAfterHit) { + this.goOnAfterHit = goOnAfterHit; + } + + public long getRemovalTime() { + return removalTime; + } + + public void setRemovalTime(long removalTime) { + this.removalTime = removalTime; + } + + public long getUseCooldown() { + return useCooldown; + } + + public void setUseCooldown(long useCooldown) { + this.useCooldown = useCooldown; + } + + public long getPrepareCooldown() { + return prepareCooldown; + } + + public void setPrepareCooldown(long prepareCooldown) { + this.prepareCooldown = prepareCooldown; + } + + public long getMaxDuration() { + return maxDuration; + } + + public void setMaxDuration(long maxDuration) { + this.maxDuration = maxDuration; + } + + public double getRange() { + return range; + } - public void setAffectingRadius(int affectingRadius) { - this.affectingRadius = affectingRadius; - } + public void setRange(double range) { + this.range = range; + } - public double getDamage() { - return damage; - } + public double getPrepareRange() { + return prepareRange; + } + + public void setPrepareRange(double prepareRange) { + this.prepareRange = prepareRange; + } - public void setDamage(double damage) { - this.damage = damage; - } + public double getSourceKeepRange() { + return sourceKeepRange; + } - public boolean isAllowChangeDirection() { - return allowChangeDirection; - } + public void setSourceKeepRange(double sourceKeepRange) { + this.sourceKeepRange = sourceKeepRange; + } - public void setAllowChangeDirection(boolean allowChangeDirection) { - this.allowChangeDirection = allowChangeDirection; - } + public int getAffectingRadius() { + return affectingRadius; + } - @Override - public void load() {} + public void setAffectingRadius(int affectingRadius) { + this.affectingRadius = affectingRadius; + } - @Override - public void stop() {} + public double getDamage() { + return damage; + } - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.EarthLine.Enabled"); - } + public void setDamage(double damage) { + this.damage = damage; + } + + public boolean isAllowChangeDirection() { + return allowChangeDirection; + } + + public void setAllowChangeDirection(boolean allowChangeDirection) { + this.allowChangeDirection = allowChangeDirection; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.EarthLine.Enabled"); + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/EarthPillar.java b/src/com/jedk1/jedcore/ability/earthbending/EarthPillar.java index 1935c15..2067b0c 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/EarthPillar.java +++ b/src/com/jedk1/jedcore/ability/earthbending/EarthPillar.java @@ -8,7 +8,6 @@ import com.projectkorra.projectkorra.earthbending.Collapse; import com.projectkorra.projectkorra.util.BlockSource; import com.projectkorra.projectkorra.util.ClickType; - import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -22,195 +21,195 @@ public class EarthPillar extends EarthAbility implements AddonAbility { - private static final ConcurrentHashMap AFFECTED_BLOCKS = new ConcurrentHashMap<>(); - private static final ConcurrentHashMap> AFFECTED = new ConcurrentHashMap<>(); - - private Block block; - private BlockFace face; - @Attribute(Attribute.HEIGHT) - private int height; - @Attribute(Attribute.RANGE) - private int range; - private int step; - - private final List blocks = new ArrayList<>(); - - public EarthPillar(Player player) { - super(player); - - if (!bPlayer.canBend(this)) { - return; - } - - setFields(); - Block target = BlockSource.getEarthSourceBlock(player, range, ClickType.SHIFT_DOWN); - if (target != null && !AFFECTED_BLOCKS.containsKey(target)) { - List blocks = player.getLastTwoTargetBlocks(null, range); - if (blocks.size() > 1) { - this.player = player; - face = blocks.get(1).getFace(blocks.get(0)); - block = blocks.get(1); - height = getEarthbendableBlocksLength(block, getDirection(face).clone().multiply(-1), height); - start(); - } - } else if (target != null && AFFECTED_BLOCKS.containsKey(target)) { - List blocks = AFFECTED.get(AFFECTED_BLOCKS.get(target)); - if (blocks != null && !blocks.isEmpty()) { - for (Block b : blocks) { - Collapse.revertBlock(b); - } - playEarthbendingSound(target.getLocation()); - AFFECTED.remove(AFFECTED_BLOCKS.get(target)); - } - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - height = config.getInt("Abilities.Earth.EarthPillar.Height"); - range = config.getInt("Abilities.Earth.EarthPillar.Range"); - } - - @Override - public void progress() { - if (step < height) { - step++; - movePillar(); - } else { - AFFECTED.put(this, blocks); - remove(); - } - } - - private void movePillar() { - moveEarth(block, getDirection(face), height); - block = block.getRelative(face); - AFFECTED_BLOCKS.put(block, this); - blocks.add(block); - } - - private Vector getDirection(BlockFace face) { - switch (face) { - case UP: - return new Vector(0, 1, 0); - case DOWN: - return new Vector(0, -1, 0); - case NORTH: - return new Vector(0, 0, -1); - case SOUTH: - return new Vector(0, 0, 1); - case EAST: - return new Vector(1, 0, 0); - case WEST: - return new Vector(-1, 0, 0); - default: - return null; - } - } - - public static void progressAll() { - for (Block block : AFFECTED_BLOCKS.keySet()) { - if (!EarthAbility.isEarthbendable(AFFECTED_BLOCKS.get(block).getPlayer(), block)) { - AFFECTED_BLOCKS.remove(block); - } - } - } - - @Override - public long getCooldown() { - return 0; - } - - @Override - public Location getLocation() { - return block != null ? block.getLocation() : null; - } - - @Override - public String getName() { - return "EarthPillar"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthPillar.Description"); - } - - public Block getBlock() { - return block; - } - - public void setBlock(Block block) { - this.block = block; - } - - public BlockFace getFace() { - return face; - } - - public void setFace(BlockFace face) { - this.face = face; - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public int getRange() { - return range; - } - - public void setRange(int range) { - this.range = range; - } - - public int getStep() { - return step; - } - - public void setStep(int step) { - this.step = step; - } - - public List getBlocks() { - return blocks; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.EarthPillar.Enabled"); - } + private static final ConcurrentHashMap AFFECTED_BLOCKS = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap> AFFECTED = new ConcurrentHashMap<>(); + + private Block block; + private BlockFace face; + @Attribute(Attribute.HEIGHT) + private int height; + @Attribute(Attribute.RANGE) + private int range; + private int step; + + private final List blocks = new ArrayList<>(); + + public EarthPillar(Player player) { + super(player); + + if (!bPlayer.canBend(this)) { + return; + } + + setFields(); + Block target = BlockSource.getEarthSourceBlock(player, range, ClickType.SHIFT_DOWN); + if (target != null && !AFFECTED_BLOCKS.containsKey(target)) { + List blocks = player.getLastTwoTargetBlocks(null, range); + if (blocks.size() > 1) { + this.player = player; + face = blocks.get(1).getFace(blocks.get(0)); + block = blocks.get(1); + height = getEarthbendableBlocksLength(block, getDirection(face).clone().multiply(-1), height); + start(); + } + } else if (target != null && AFFECTED_BLOCKS.containsKey(target)) { + List blocks = AFFECTED.get(AFFECTED_BLOCKS.get(target)); + if (blocks != null && !blocks.isEmpty()) { + for (Block b : blocks) { + Collapse.revertBlock(b); + } + playEarthbendingSound(target.getLocation()); + AFFECTED.remove(AFFECTED_BLOCKS.get(target)); + } + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + height = config.getInt("Abilities.Earth.EarthPillar.Height"); + range = config.getInt("Abilities.Earth.EarthPillar.Range"); + } + + @Override + public void progress() { + if (step < height) { + step++; + movePillar(); + } else { + AFFECTED.put(this, blocks); + remove(); + } + } + + private void movePillar() { + moveEarth(block, getDirection(face), height); + block = block.getRelative(face); + AFFECTED_BLOCKS.put(block, this); + blocks.add(block); + } + + private Vector getDirection(BlockFace face) { + switch (face) { + case UP: + return new Vector(0, 1, 0); + case DOWN: + return new Vector(0, -1, 0); + case NORTH: + return new Vector(0, 0, -1); + case SOUTH: + return new Vector(0, 0, 1); + case EAST: + return new Vector(1, 0, 0); + case WEST: + return new Vector(-1, 0, 0); + default: + return null; + } + } + + public static void progressAll() { + for (Block block : AFFECTED_BLOCKS.keySet()) { + if (!EarthAbility.isEarthbendable(AFFECTED_BLOCKS.get(block).getPlayer(), block)) { + AFFECTED_BLOCKS.remove(block); + } + } + } + + @Override + public long getCooldown() { + return 0; + } + + @Override + public Location getLocation() { + return block != null ? block.getLocation() : null; + } + + @Override + public String getName() { + return "EarthPillar"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthPillar.Description"); + } + + public Block getBlock() { + return block; + } + + public void setBlock(Block block) { + this.block = block; + } + + public BlockFace getFace() { + return face; + } + + public void setFace(BlockFace face) { + this.face = face; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public int getStep() { + return step; + } + + public void setStep(int step) { + this.step = step; + } + + public List getBlocks() { + return blocks; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.EarthPillar.Enabled"); + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/EarthShard.java b/src/com/jedk1/jedcore/ability/earthbending/EarthShard.java index 96c34e1..04a2fe4 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/EarthShard.java +++ b/src/com/jedk1/jedcore/ability/earthbending/EarthShard.java @@ -1,449 +1,531 @@ package com.jedk1.jedcore.ability.earthbending; -import java.util.*; -import java.util.stream.Collectors; - +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.collision.AABB; import com.jedk1.jedcore.collision.CollisionDetector; import com.jedk1.jedcore.collision.CollisionUtil; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.util.BlockUtil; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.earthbending.passive.DensityShift; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Entity; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; -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.stream.Collectors; public class EarthShard extends EarthAbility implements AddonAbility { - @Attribute(Attribute.RANGE) - public static int range; - public static int abilityRange; - - @Attribute(Attribute.DAMAGE) - public static double normalDmg; - @Attribute(Attribute.DAMAGE) - public static double metalDmg; - - @Attribute("MaxShots") - public static int maxShards; - @Attribute(Attribute.COOLDOWN) - public static long cooldown; - - private boolean isThrown = false; - private Location origin; - private double abilityCollisionRadius; - private double entityCollisionRadius; - - private final List tblockTracker = new ArrayList<>(); - private final List readyBlocksTracker = new ArrayList<>(); - private final List fallingBlocks = new ArrayList<>(); - - public EarthShard(Player player) { - super(player); - - if (!bPlayer.canBend(this)) { - return; - } - - if (hasAbility(player, EarthShard.class)) { - for (EarthShard es : EarthShard.getAbilities(player, EarthShard.class)) { - if (es.isThrown && System.currentTimeMillis() - es.getStartTime() >= 20000) { - // Remove the old instance because it got into a broken state. - // This shouldn't affect normal gameplay because the cooldown is long enough that the - // shards should have already hit their target. - es.remove(); - } else { - es.select(); - return; - } - } - } - - setFields(); - origin = player.getLocation().clone(); - raiseEarthBlock(getEarthSourceBlock(range)); - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - range = config.getInt("Abilities.Earth.EarthShard.PrepareRange"); - abilityRange = config.getInt("Abilities.Earth.EarthShard.AbilityRange"); - normalDmg = config.getDouble("Abilities.Earth.EarthShard.Damage.Normal"); - metalDmg = config.getDouble("Abilities.Earth.EarthShard.Damage.Metal"); - maxShards = config.getInt("Abilities.Earth.EarthShard.MaxShards"); - cooldown = config.getLong("Abilities.Earth.EarthShard.Cooldown"); - abilityCollisionRadius = config.getDouble("Abilities.Earth.EarthShard.AbilityCollisionRadius"); - entityCollisionRadius = config.getDouble("Abilities.Earth.EarthShard.EntityCollisionRadius"); - } - - public void select() { - raiseEarthBlock(getEarthSourceBlock(range)); - } - - public void raiseEarthBlock(Block block) { - if (block == null) { - return; - } - - if (tblockTracker.size() >= maxShards) { - return; - } - - Vector blockVector = block.getLocation().toVector().toBlockVector().setY(0); - - // Don't select from locations that already have an EarthShard block. - for (TempBlock tempBlock : tblockTracker) { - if (tempBlock.getLocation().getWorld() != block.getWorld()) { - continue; - } - - Vector tempBlockVector = tempBlock.getLocation().toVector().toBlockVector().setY(0); - - if (tempBlockVector.equals(blockVector)) { - return; - } - } - - for (int i = 1; i < 4; i++) { - if (!isTransparent(block.getRelative(BlockFace.UP, i))) { - return; - } - } - - if (isEarthbendable(block)) { - if (isMetal(block)) { - playMetalbendingSound(block.getLocation()); - } else { - ParticleEffect.BLOCK_CRACK.display(block.getLocation().add(0, 1, 0), 20, 0.0, 0.0, 0.0, 0.0, block.getBlockData()); - playEarthbendingSound(block.getLocation()); - } - - Material material = getCorrectType(block); - - if (DensityShift.isPassiveSand(block)) { - DensityShift.revertSand(block); - } - - Location loc = block.getLocation().add(0.5, 0, 0.5); - new TempFallingBlock(loc, material.createBlockData(), new Vector(0, 0.8, 0), this); - TempBlock tb = new TempBlock(block, Material.AIR.createBlockData()); - tblockTracker.add(tb); - } - } - - public Material getCorrectType(Block block) { - if (block.getType() == Material.SAND) { - return Material.SANDSTONE; - } - if (block.getType() == Material.RED_SAND) { - return Material.RED_SANDSTONE; - } - if (block.getType() == Material.GRAVEL) { - return Material.COBBLESTONE; - } - if (block.getType().name().endsWith("CONCRETE_POWDER")) { - return Material.getMaterial(block.getType().name().replace("_POWDER", "")); - } - - return block.getType(); - } - - public void progress() { - if (player == null || !player.isOnline() || player.isDead()) { - remove(); - return; - } - - if (!isThrown) { - if (!bPlayer.canBendIgnoreCooldowns(this)) { - remove(); - return; - } - - if (tblockTracker.isEmpty()) { - remove(); - return; - } - - for (TempFallingBlock tfb : TempFallingBlock.getFromAbility(this)) { - FallingBlock fb = tfb.getFallingBlock(); - - if (fb.isDead() || fb.getLocation().getBlockY() == origin.getBlockY() + 2) { - TempBlock tb = new TempBlock(fb.getLocation().getBlock(), fb.getBlockData()); - readyBlocksTracker.add(tb); - tfb.remove(); - } - } - } else { - for (TempFallingBlock tfb : TempFallingBlock.getFromAbility(this)) { - FallingBlock fb = tfb.getFallingBlock(); - - AABB collider = BlockUtil.getFallingBlockBoundsFull(fb).scale(entityCollisionRadius * 2.0); - - CollisionDetector.checkEntityCollisions(player, collider, (e) -> { - DamageHandler.damageEntity(e, isMetal(fb.getBlockData().getMaterial()) ? metalDmg : normalDmg, this); - ((LivingEntity) e).setNoDamageTicks(0); - ParticleEffect.BLOCK_CRACK.display(fb.getLocation(), 20, 0, 0, 0, 0, fb.getBlockData()); - tfb.remove(); - return false; - }); - - if (fb.isDead()) { - tfb.remove(); - } - } - - if (TempFallingBlock.getFromAbility(this).isEmpty()) { - remove(); - } - } - } - - public static void throwShard(Player player) { - if (hasAbility(player, EarthShard.class)) { - for (EarthShard es : EarthShard.getAbilities(player, EarthShard.class)) { - if (!es.isThrown) { - es.throwShard(); - break; - } - } - } - } - - public void throwShard() { - if (isThrown || tblockTracker.size() > readyBlocksTracker.size()) { - return; - } - - Location targetLocation = GeneralMethods.getTargetedLocation(player, abilityRange); - - if (GeneralMethods.getTargetedEntity(player, abilityRange, new ArrayList<>()) != null) { - targetLocation = GeneralMethods.getTargetedEntity(player, abilityRange, new ArrayList<>()).getLocation(); - } - - Vector vel = null; - - for (TempBlock tb : readyBlocksTracker) { - Location target = player.getTargetBlock(null, 30).getLocation(); - - if (target.getBlockX() == tb.getBlock().getX() && target.getBlockY() == tb.getBlock().getY() && target.getBlockZ() == tb.getBlock().getZ()) { - vel = player.getEyeLocation().getDirection().multiply(2).add(new Vector(0, 0.2, 0)); - break; - } - - vel = GeneralMethods.getDirection(tb.getLocation(), targetLocation).normalize().multiply(2).add(new Vector(0, 0.2, 0)); - } - - for (TempBlock tb : readyBlocksTracker) { - fallingBlocks.add(new TempFallingBlock(tb.getLocation(), tb.getBlock().getBlockData(), vel, this)); - tb.revertBlock(); - } - - revertBlocks(); - - isThrown = true; - - if (player.isOnline()) { - bPlayer.addCooldown(this); - } - } - - public void revertBlocks() { - for (TempBlock tb : tblockTracker) { - tb.revertBlock(); - } - - for (TempBlock tb : readyBlocksTracker) { - tb.revertBlock(); - } - - tblockTracker.clear(); - readyBlocksTracker.clear(); - } - - @Override - public void remove() { - // Destroy any remaining falling blocks. - for (TempFallingBlock tfb : TempFallingBlock.getFromAbility(this)) { - tfb.remove(); - } - - revertBlocks(); - - super.remove(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public List getLocations() { - return fallingBlocks.stream().map(TempFallingBlock::getLocation).collect(Collectors.toList()); - } - - @Override - public void handleCollision(Collision collision) { - CollisionUtil.handleFallingBlockCollisions(collision, fallingBlocks); - } - - @Override - public double getCollisionRadius() { - return abilityCollisionRadius; - } - - @Override - public String getName() { - return "EarthShard"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthShard.Description"); - } - - public static int getRange() { - return range; - } - - public static void setRange(int range) { - EarthShard.range = range; - } - - public static int getAbilityRange() { - return abilityRange; - } - - public static void setAbilityRange(int abilityRange) { - EarthShard.abilityRange = abilityRange; - } - - public static double getNormalDmg() { - return normalDmg; - } - - public static void setNormalDmg(double normalDmg) { - EarthShard.normalDmg = normalDmg; - } - - public static double getMetalDmg() { - return metalDmg; - } - - public static void setMetalDmg(double metalDmg) { - EarthShard.metalDmg = metalDmg; - } - - public static int getMaxShards() { - return maxShards; - } - - public static void setMaxShards(int maxShards) { - EarthShard.maxShards = maxShards; - } - - public static void setCooldown(long cooldown) { - EarthShard.cooldown = cooldown; - } - - public boolean isThrown() { - return isThrown; - } - - public void setThrown(boolean thrown) { - isThrown = thrown; - } - - public Location getOrigin() { - return origin; - } - - public void setOrigin(Location origin) { - this.origin = origin; - } - - public double getAbilityCollisionRadius() { - return abilityCollisionRadius; - } - - public void setAbilityCollisionRadius(double abilityCollisionRadius) { - this.abilityCollisionRadius = abilityCollisionRadius; - } - - public double getEntityCollisionRadius() { - return entityCollisionRadius; - } - - public void setEntityCollisionRadius(double entityCollisionRadius) { - this.entityCollisionRadius = entityCollisionRadius; - } - - public List getTblockTracker() { - return tblockTracker; - } - - public List getReadyBlocksTracker() { - return readyBlocksTracker; - } - - public List getFallingBlocks() { - return fallingBlocks; - } - - @Override - public void load() {} - - @Override - public void stop() {} + @Attribute(Attribute.RANGE) + public static int range; + public static int abilityRange; + + @Attribute(Attribute.DAMAGE) + public static double normalDmg; + @Attribute(Attribute.DAMAGE) + public static double metalDmg; + + @Attribute("MaxShots") + public static int maxShards; + @Attribute(Attribute.COOLDOWN) + public static long cooldown; + + private boolean isThrown = false; + private Location origin; + private double abilityCollisionRadius; + private double entityCollisionRadius; + + private final List tblockTracker = new ArrayList<>(); + private final List readyBlocksTracker = new ArrayList<>(); + private final List fallingBlocks = new ArrayList<>(); + + private boolean allowKnockup; + private double knockupVelocity; + private double knockupRange; + + private boolean allowKnockupSelf; + private double knockupSelfVelocity; + private double knockupSelfRange; + + public EarthShard(Player player) { + super(player); + + if (!bPlayer.canBend(this)) { + return; + } + + if (hasAbility(player, EarthShard.class)) { + for (EarthShard es : EarthShard.getAbilities(player, EarthShard.class)) { + if (es.isThrown && System.currentTimeMillis() - es.getStartTime() >= 20000) { + // Remove the old instance because it got into a broken state. + // This shouldn't affect normal gameplay because the cooldown is long enough that the + // shards should have already hit their target. + es.remove(); + } else { + es.select(); + return; + } + } + } + + setFields(); + origin = player.getLocation().clone(); + raiseEarthBlock(getEarthSourceBlock(range)); + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + range = config.getInt("Abilities.Earth.EarthShard.PrepareRange"); + abilityRange = config.getInt("Abilities.Earth.EarthShard.AbilityRange"); + normalDmg = config.getDouble("Abilities.Earth.EarthShard.Damage.Normal"); + metalDmg = config.getDouble("Abilities.Earth.EarthShard.Damage.Metal"); + maxShards = config.getInt("Abilities.Earth.EarthShard.MaxShards"); + cooldown = config.getLong("Abilities.Earth.EarthShard.Cooldown"); + abilityCollisionRadius = config.getDouble("Abilities.Earth.EarthShard.AbilityCollisionRadius"); + entityCollisionRadius = config.getDouble("Abilities.Earth.EarthShard.EntityCollisionRadius"); + allowKnockup = config.getBoolean("Abilities.Earth.EarthShard.KnockUp.Others.Allow"); + knockupVelocity = config.getDouble("Abilities.Earth.EarthShard.KnockUp.Others.Velocity"); + knockupRange = config.getDouble("Abilities.Earth.EarthShard.KnockUp.Others.Range"); + allowKnockupSelf = config.getBoolean("Abilities.Earth.EarthShard.KnockUp.Self.Allow"); + knockupSelfVelocity = config.getDouble("Abilities.Earth.EarthShard.KnockUp.Self.Velocity"); + knockupSelfRange = config.getDouble("Abilities.Earth.EarthShard.KnockUp.Self.Range"); + } + + public void select() { + raiseEarthBlock(getEarthSourceBlock(range)); + } + + public void raiseEarthBlock(Block block) { + if (block == null) return; + if (EarthAbility.getMovedEarth().containsKey(block)) return; + if (tblockTracker.size() >= maxShards) return; + + Vector blockVector = block.getLocation().toVector().toBlockVector().setY(0); + + for (TempBlock tempBlock : tblockTracker) { + if (tempBlock.getLocation().getWorld() != block.getWorld()) continue; + + Vector tempBlockVector = tempBlock.getLocation().toVector().toBlockVector().setY(0); + if (tempBlockVector.equals(blockVector)) return; + } + + for (int i = 1; i < 4; i++) { + if (!isTransparent(block.getRelative(BlockFace.UP, i))) return; + } + + if (!isEarthbendable(block)) return; + + if (isMetal(block)) { + playMetalbendingSound(block.getLocation()); + } else { + ParticleEffect.BLOCK_CRACK.display( + block.getLocation().add(0, 1, 0), 20, 0.0, 0.0, 0.0, 0.0, block.getBlockData() + ); + playEarthbendingSound(block.getLocation()); + } + + Material material = getCorrectType(block); + + if (DensityShift.isPassiveSand(block)) { + DensityShift.revertSand(block); + } + + Location loc = block.getLocation().add(0.5, 0, 0.5); + new TempFallingBlock(loc, material.createBlockData(), new Vector(0, 0.8, 0), this); + TempBlock tb = new TempBlock(block, Material.AIR.createBlockData()); + tblockTracker.add(tb); + + handleKnockup(block); + } + + private void handleKnockup(Block origin) { + if (!allowKnockup && !allowKnockupSelf) return; + + Location originLoc = origin.getLocation(); + World world = origin.getWorld(); + + for (Entity entity : world.getNearbyEntities(originLoc, Math.max(knockupRange, knockupSelfRange), knockupRange, knockupRange)) { + if (entity instanceof FallingBlock) continue; + + if (entity.equals(player)) { + if (!allowKnockupSelf) continue; + if (entity.getLocation().distance(originLoc) <= knockupSelfRange) { + entity.setVelocity(entity.getVelocity().add(new Vector(0, knockupSelfVelocity, 0))); + } + } else { + if (!allowKnockup) continue; + if (entity.getLocation().distance(originLoc) <= knockupRange) { + entity.setVelocity(entity.getVelocity().add(new Vector(0, knockupVelocity, 0))); + } + } + } + } + + public Material getCorrectType(Block block) { + if (block.getType() == Material.SAND) { + return Material.SANDSTONE; + } + if (block.getType() == Material.RED_SAND) { + return Material.RED_SANDSTONE; + } + if (block.getType() == Material.GRAVEL) { + return Material.COBBLESTONE; + } + if (block.getType().name().endsWith("CONCRETE_POWDER")) { + return Material.getMaterial(block.getType().name().replace("_POWDER", "")); + } + + return block.getType(); + } + + public void progress() { + if (player == null || !player.isOnline() || player.isDead()) { + remove(); + return; + } + + if (!isThrown) { + if (!bPlayer.canBendIgnoreCooldowns(this)) { + remove(); + return; + } + + if (tblockTracker.isEmpty()) { + remove(); + return; + } + + // iterate over a defensive copy to avoid ConcurrentModificationException + for (TempFallingBlock tfb : new ArrayList<>(TempFallingBlock.getFromAbility(this))) { + FallingBlock fb = tfb.getFallingBlock(); + + if (fb.isDead() || fb.getLocation().getBlockY() == origin.getBlockY() + 2) { + TempBlock tb = new TempBlock(fb.getLocation().getBlock(), fb.getBlockData()); + readyBlocksTracker.add(tb); + tfb.remove(); + } + } + } else { + // iterate over a defensive copy to avoid ConcurrentModificationException + for (TempFallingBlock tfb : new ArrayList<>(TempFallingBlock.getFromAbility(this))) { + FallingBlock fb = tfb.getFallingBlock(); + + AABB collider = BlockUtil.getFallingBlockBoundsFull(fb).scale(entityCollisionRadius * 2.0); + + CollisionDetector.checkEntityCollisions(player, collider, (e) -> { + DamageHandler.damageEntity(e, isMetal(fb.getBlockData().getMaterial()) ? metalDmg : normalDmg, this); + ((LivingEntity) e).setNoDamageTicks(0); + ParticleEffect.BLOCK_CRACK.display(fb.getLocation(), 20, 0, 0, 0, 0, fb.getBlockData()); + tfb.remove(); + return false; + }); + + if (fb.isDead()) { + tfb.remove(); + } + } + + if (TempFallingBlock.getFromAbility(this).isEmpty()) { + remove(); + } + } + } + + public static void throwShard(Player player) { + if (hasAbility(player, EarthShard.class)) { + for (EarthShard es : EarthShard.getAbilities(player, EarthShard.class)) { + if (!es.isThrown) { + es.throwShard(); + break; + } + } + } + } + + public void throwShard() { + if (isThrown || tblockTracker.size() > readyBlocksTracker.size()) { + return; + } + + Location targetLocation = GeneralMethods.getTargetedLocation(player, abilityRange); + + if (GeneralMethods.getTargetedEntity(player, abilityRange, new ArrayList<>()) != null) { + targetLocation = GeneralMethods.getTargetedEntity(player, abilityRange, new ArrayList<>()).getLocation(); + } + + Vector vel = null; + + for (TempBlock tb : readyBlocksTracker) { + Location target = player.getTargetBlock(null, 30).getLocation(); + + if (target.getBlockX() == tb.getBlock().getX() && target.getBlockY() == tb.getBlock().getY() && target.getBlockZ() == tb.getBlock().getZ()) { + vel = player.getEyeLocation().getDirection().multiply(2).add(new Vector(0, 0.2, 0)); + break; + } + + vel = GeneralMethods.getDirection(tb.getLocation(), targetLocation).normalize().multiply(2).add(new Vector(0, 0.2, 0)); + } + + for (TempBlock tb : readyBlocksTracker) { + fallingBlocks.add(new TempFallingBlock(tb.getLocation(), tb.getBlock().getBlockData(), vel, this)); + tb.revertBlock(); + } + + revertBlocks(); + + isThrown = true; + + if (player.isOnline()) { + bPlayer.addCooldown(this); + } + } + + public void revertBlocks() { + for (TempBlock tb : tblockTracker) { + tb.revertBlock(); + } + + for (TempBlock tb : readyBlocksTracker) { + tb.revertBlock(); + } + + tblockTracker.clear(); + readyBlocksTracker.clear(); + } + + @Override + public void remove() { + // Destroy any remaining falling blocks. + // iterate over a defensive copy to avoid ConcurrentModificationException + for (TempFallingBlock tfb : new ArrayList<>(TempFallingBlock.getFromAbility(this))) { + tfb.remove(); + } + + revertBlocks(); + + super.remove(); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public List getLocations() { + return fallingBlocks.stream().map(TempFallingBlock::getLocation).collect(Collectors.toList()); + } + + @Override + public void handleCollision(Collision collision) { + CollisionUtil.handleFallingBlockCollisions(collision, fallingBlocks); + } + + @Override + public double getCollisionRadius() { + return abilityCollisionRadius; + } + + @Override + public String getName() { + return "EarthShard"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthShard.Description"); + } + + public static int getRange() { + return range; + } + + public static void setRange(int range) { + EarthShard.range = range; + } + + public static int getAbilityRange() { + return abilityRange; + } + + public static void setAbilityRange(int abilityRange) { + EarthShard.abilityRange = abilityRange; + } + + public static double getNormalDmg() { + return normalDmg; + } + + public static void setNormalDmg(double normalDmg) { + EarthShard.normalDmg = normalDmg; + } + + public static double getMetalDmg() { + return metalDmg; + } + + public static void setMetalDmg(double metalDmg) { + EarthShard.metalDmg = metalDmg; + } + + public static int getMaxShards() { + return maxShards; + } + + public static void setMaxShards(int maxShards) { + EarthShard.maxShards = maxShards; + } + + public static void setCooldown(long cooldown) { + EarthShard.cooldown = cooldown; + } + + public boolean isThrown() { + return isThrown; + } + + public void setThrown(boolean thrown) { + isThrown = thrown; + } + + public Location getOrigin() { + return origin; + } + + public void setOrigin(Location origin) { + this.origin = origin; + } + + public double getAbilityCollisionRadius() { + return abilityCollisionRadius; + } + + public void setAbilityCollisionRadius(double abilityCollisionRadius) { + this.abilityCollisionRadius = abilityCollisionRadius; + } + + public double getEntityCollisionRadius() { + return entityCollisionRadius; + } + + public void setEntityCollisionRadius(double entityCollisionRadius) { + this.entityCollisionRadius = entityCollisionRadius; + } + + public List getTblockTracker() { + return tblockTracker; + } + + public List getReadyBlocksTracker() { + return readyBlocksTracker; + } + + public List getFallingBlocks() { + return fallingBlocks; + } + + public boolean isAllowKnockup() { + return allowKnockup; + } + + public void setAllowKnockup(boolean allowKnockup) { + this.allowKnockup = allowKnockup; + } + + public double getKnockupVelocity() { + return knockupVelocity; + } + + public void setKnockupVelocity(double knockupVelocity) { + this.knockupVelocity = knockupVelocity; + } + + public double getKnockupRange() { + return knockupRange; + } + + public void setKnockupRange(double knockupRange) { + this.knockupRange = knockupRange; + } + + public boolean isAllowKnockupSelf() { + return allowKnockupSelf; + } + + public void setAllowKnockupSelf(boolean allowKnockupSelf) { + this.allowKnockupSelf = allowKnockupSelf; + } + + public double getKnockupSelfVelocity() { + return knockupSelfVelocity; + } + + public void setKnockupSelfVelocity(double knockupSelfVelocity) { + this.knockupSelfVelocity = knockupSelfVelocity; + } + + public double getKnockupSelfRange() { + return knockupSelfRange; + } + + public void setKnockupSelfRange(double knockupSelfRange) { + this.knockupSelfRange = knockupSelfRange; + } + + @Override + public void load() {} + + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.EarthShard.Enabled"); - } + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.EarthShard.Enabled"); + } } diff --git a/src/com/jedk1/jedcore/ability/earthbending/EarthSurf.java b/src/com/jedk1/jedcore/ability/earthbending/EarthSurf.java index 83df672..425962b 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/EarthSurf.java +++ b/src/com/jedk1/jedcore/ability/earthbending/EarthSurf.java @@ -12,7 +12,6 @@ import com.projectkorra.projectkorra.earthbending.passive.DensityShift; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.TempBlock; - import com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.Material; @@ -24,480 +23,483 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; public class EarthSurf extends EarthAbility implements AddonAbility { - private static final double TARGET_HEIGHT = 1.5; - - private Location location; - private double prevHealth; - - @Attribute(Attribute.COOLDOWN) - private long cooldown; - private long minimumCooldown; - @Attribute(Attribute.DURATION) - private long duration; - private boolean cooldownEnabled; - private boolean durationEnabled; - private boolean removeOnAnyDamage; - @Attribute(Attribute.SPEED) - private double speed; - private double springStiffness; - private final Set ridingBlocks = new HashSet<>(); - private CollisionDetector collisionDetector = new DefaultCollisionDetector(); - private DoubleSmoother heightSmoother; - - public EarthSurf(Player player) { - super(player); - - if (!bPlayer.canBend(this)) { - return; - } - - if (hasAbility(player, EarthSurf.class)) { - getAbility(player, EarthSurf.class).remove(); - return; - } - - setFields(); - - location = player.getLocation(); - - if (canStart()) { - prevHealth = player.getHealth(); - - this.flightHandler.createInstance(player, this.getName()); - player.setAllowFlight(true); - player.setFlying(false); - start(); - } - } - - private boolean canStart() { - Block beneath = getBlockBeneath(player.getLocation().clone()); - double maxHeight = getMaxHeight(); - - return isEarthbendable(player, beneath) && !isMetal(beneath) && beneath.getLocation().distanceSquared(player.getLocation()) <= maxHeight * maxHeight; - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Earth.EarthSurf.Cooldown.Cooldown"); - minimumCooldown = config.getLong("Abilities.Earth.EarthSurf.Cooldown.MinimumCooldown"); - duration = config.getLong("Abilities.Earth.EarthSurf.Duration.Duration"); - cooldownEnabled = config.getBoolean("Abilities.Earth.EarthSurf.Cooldown.Enabled"); - durationEnabled = config.getBoolean("Abilities.Earth.EarthSurf.Duration.Enabled"); - removeOnAnyDamage = config.getBoolean("Abilities.Earth.EarthSurf.RemoveOnAnyDamage"); - speed = config.getDouble("Abilities.Earth.EarthSurf.Speed"); - springStiffness = config.getDouble("Abilities.Earth.EarthSurf.SpringStiffness"); - - int smootherSize = config.getInt("Abilities.Earth.EarthSurf.HeightTolerance"); - this.heightSmoother = new DoubleSmoother(Math.max(smootherSize, 1)); - - if (config.getBoolean("Abilities.Earth.EarthSurf.RelaxedCollisions")) { - this.collisionDetector = new RelaxedCollisionDetector(); - } - - if (!config.getBoolean("Abilities.Earth.EarthSurf.Cooldown.Scaled")) { - minimumCooldown = cooldown; - } - } - - @Override - public void progress() { - if (shouldRemove()) { - remove(); - return; - } - - this.player.setFlying(false); - - if (!collisionDetector.isColliding(player) && player.getHealth() >= prevHealth) { - movePlayer(); - - if (removeOnAnyDamage) { - prevHealth = player.getHealth(); - } - } else { - remove(); - } - } - - private boolean shouldRemove() { - if (player == null || player.isDead() || !player.isOnline()) return true; - if (!bPlayer.canBendIgnoreCooldowns(this)) return true; - if (!isEarthbendable(player, getBlockBeneath(player.getLocation().clone()))) return true; - if (durationEnabled && System.currentTimeMillis() > getStartTime() + duration) return true; - - return player.isSneaking(); - } - - private void movePlayer() { - location = player.getEyeLocation().clone(); - location.setPitch(0); - Vector direction = location.getDirection().normalize(); - - // How far the player is above the ground. - double height = getPlayerDistance(); - double maxHeight = getMaxHeight(); - double smoothedHeight = heightSmoother.add(height); - - // Destroy ability if player gets too far from ground. - if (smoothedHeight > maxHeight) { - remove(); - return; - } - - // Calculate the spring force to push the player back to the target height. - double displacement = height - TARGET_HEIGHT; - double force = -springStiffness * displacement; - - double maxForce = 0.5; - if (Math.abs(force) > maxForce) { - // Cap the force to maxForce so the player isn't instantly pulled to the ground. - force = force / Math.abs(force) * maxForce; - } - - Vector velocity = direction.clone().multiply(speed).setY(force); - - rideWave(); - - player.setVelocity(velocity); - player.setFallDistance(0); - } - - private double getMaxHeight() { - return TARGET_HEIGHT + 2.0; - } - - private double getPlayerDistance() { - Location l = player.getLocation().clone(); - while (true) { - if (l.getBlockY() <= l.getWorld().getMinHeight()) break; - if (ElementalAbility.isAir(l.getBlock().getType()) && ridingBlocks.contains(l.getBlock())) break; - if (GeneralMethods.isSolid(l.getBlock())) break; - - l.add(0, -0.1, 0); - } - return player.getLocation().getY() - l.getY(); - } - - private Block getBlockBeneath(Location l) { - while (l.getBlockY() > l.getWorld().getMinHeight() && MaterialUtil.isTransparent(l.getBlock())) { - l.add(0, -0.5, 0); - } - return l.getBlock(); - } - - private void rideWave() { - for (int i = 0; i < 3; i++) { - Location loc = location.clone(); - if (i < 2) - loc.add(getSideDirection(i)); - - //Player Positioning - double distOffset = 2.5; - Location bL = loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()); - while (!ElementalAbility.isAir(loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()).getBlock().getType())) { - loc.add(0, 0.1, 0); - } - - if (isEarthbendable(player, getBlockBeneath(loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()))) && getBlockBeneath(bL) != null) { - Block block = loc.clone().add(0, -3.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset - 0.5)).toLocation(player.getWorld()).getBlock(); - Location temp = loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()); - - if (RegionProtection.isRegionProtected(this, block.getLocation())) { - continue; - } - // Don't render blocks above the player because it looks bad. - // TODO: Change this check to see if it's a reachable position instead. - if (block.getLocation().getY() > this.player.getLocation().getY()) { - continue; - } - - if (DensityShift.isPassiveSand(block)) { - DensityShift.revertSand(block); - } - - if (!GeneralMethods.isSolid(block.getLocation().add(0, 1, 0).getBlock()) && !ElementalAbility.isAir(block.getLocation().add(0, 1, 0).getBlock().getType())) { - if (DensityShift.isPassiveSand(block.getRelative(BlockFace.UP))) { - DensityShift.revertSand(block.getRelative(BlockFace.UP)); - } - - new TempBlock(block.getRelative(BlockFace.UP), Material.AIR.createBlockData()); - } - - if (GeneralMethods.isSolid(block)) { - ridingBlocks.add(block); - new RegenTempBlock(block, Material.AIR, Material.AIR.createBlockData(), 1000L, true, ridingBlocks::remove); - } else { - new RegenTempBlock(block, Material.AIR, Material.AIR.createBlockData(), 1000L); - } - - new TempFallingBlock(temp, getBlockBeneath(bL).getBlockData(), new Vector(0, 0.25, 0), this, true); - - for (Entity e : GeneralMethods.getEntitiesAroundPoint(loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()), 1.5D)) { - if (e instanceof LivingEntity && e.getEntityId() != player.getEntityId()) { - e.setVelocity(new Vector(0, 0.3, 0)); - } - } - } - } - } - - private Vector getSideDirection(int side) { - Vector direction = location.clone().getDirection().normalize(); - switch (side) { - case 0: // RIGHT - return new Vector(-direction.getZ(), 0.0, direction.getX()).normalize(); - case 1: // LEFT - return new Vector(direction.getZ(), 0.0, -direction.getX()).normalize(); - default: - break; - } - - return null; - } - - @Override - public void remove() { - this.flightHandler.removeInstance(player, this.getName()); - - if (cooldownEnabled && player.isOnline()) { - long scaledCooldown = cooldown; - - if (durationEnabled && duration > 0) { - double t = Math.min((System.currentTimeMillis() - this.getStartTime()) / (double) duration, 1.0); - scaledCooldown = Math.max((long) (cooldown * t), minimumCooldown); - } - - bPlayer.addCooldown(this, scaledCooldown); - } - - super.remove(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public String getName() { - return "EarthSurf"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthSurf.Description"); - } - - public static double getTargetHeight() { - return TARGET_HEIGHT; - } - - public void setLocation(Location location) { - this.location = location; - } - - public double getPrevHealth() { - return prevHealth; - } - - public void setPrevHealth(double prevHealth) { - this.prevHealth = prevHealth; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getMinimumCooldown() { - return minimumCooldown; - } - - public void setMinimumCooldown(long minimumCooldown) { - this.minimumCooldown = minimumCooldown; - } - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - public boolean isCooldownEnabled() { - return cooldownEnabled; - } - - public void setCooldownEnabled(boolean cooldownEnabled) { - this.cooldownEnabled = cooldownEnabled; - } - - public boolean isDurationEnabled() { - return durationEnabled; - } - - public void setDurationEnabled(boolean durationEnabled) { - this.durationEnabled = durationEnabled; - } - - public boolean isRemoveOnAnyDamage() { - return removeOnAnyDamage; - } - - public void setRemoveOnAnyDamage(boolean removeOnAnyDamage) { - this.removeOnAnyDamage = removeOnAnyDamage; - } - - public double getSpeed() { - return speed; - } - - public void setSpeed(double speed) { - this.speed = speed; - } - - public double getSpringStiffness() { - return springStiffness; - } - - public void setSpringStiffness(double springStiffness) { - this.springStiffness = springStiffness; - } - - public Set getRidingBlocks() { - return ridingBlocks; - } - - public CollisionDetector getCollisionDetector() { - return collisionDetector; - } - - public void setCollisionDetector(CollisionDetector collisionDetector) { - this.collisionDetector = collisionDetector; - } - - public DoubleSmoother getHeightSmoother() { - return heightSmoother; - } - - public void setHeightSmoother(DoubleSmoother heightSmoother) { - this.heightSmoother = heightSmoother; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - return config.getBoolean("Abilities.Earth.EarthSurf.Enabled"); - } - - private interface CollisionDetector { - boolean isColliding(Player player); - } - - private abstract static class AbstractCollisionDetector implements CollisionDetector { - protected boolean isCollision(Location location) { - Block block = location.getBlock(); - return !MaterialUtil.isTransparent(block) || block.isLiquid() || block.getType().isSolid(); - } - } - - private class DefaultCollisionDetector extends AbstractCollisionDetector { - @Override - public boolean isColliding(Player player) { - // The location in front of the player, where the player will be in one second. - Location front = player.getEyeLocation().clone(); - front.setPitch(0); - - Vector direction = front.getDirection().clone().setY(0).normalize(); - double playerSpeed = player.getVelocity().clone().setY(0).length(); - - front.add(direction.clone().multiply(Math.max(speed, playerSpeed))); - - for (int i = 0; i < 3; ++i) { - Location location = front.clone().add(0, -i, 0); - if (isCollision(location)) { - return true; - } - } - - return false; - } - } - - private class RelaxedCollisionDetector extends AbstractCollisionDetector { - @Override - public boolean isColliding(Player player) { - // The location in front of the player, where the player will be in one second. - Location front = player.getEyeLocation().clone().subtract(0.0, 0.5, 0.0); - front.setPitch(0); - - Vector direction = front.getDirection().clone().setY(0).normalize(); - double playerSpeed = player.getVelocity().clone().setY(0).length(); - - front.add(direction.clone().multiply(Math.max(speed, playerSpeed))); - - return isCollision(front); - } - } - - private static class DoubleSmoother { - private final double[] values; - private final int size; - private int index; - - public DoubleSmoother(int size) { - this.size = size; - this.index = 0; - - values = new double[size]; - } - - public double add(double value) { - values[index] = value; - index = (index + 1) % size; - return get(); - } - - public double get() { - return Arrays.stream(this.values).sum() / this.size; - } - } -} + private static final double TARGET_HEIGHT = 1.5; + + private Location location; + private double prevHealth; + + @Attribute(Attribute.COOLDOWN) + private long cooldown; + private long minimumCooldown; + @Attribute(Attribute.DURATION) + private long duration; + private boolean cooldownEnabled; + private boolean durationEnabled; + private boolean removeOnAnyDamage; + @Attribute(Attribute.SPEED) + private double speed; + private double springStiffness; + private final Set ridingBlocks = new HashSet<>(); + private CollisionDetector collisionDetector = new DefaultCollisionDetector(); + private DoubleSmoother heightSmoother; + + public EarthSurf(Player player) { + super(player); + + if (!bPlayer.canBend(this)) { + return; + } + + if (hasAbility(player, EarthSurf.class)) { + getAbility(player, EarthSurf.class).remove(); + return; + } + + setFields(); + + location = player.getLocation(); + + if (canStart()) { + prevHealth = player.getHealth(); + + this.flightHandler.createInstance(player, this.getName()); + player.setAllowFlight(true); + player.setFlying(false); + start(); + } + } + + private boolean canStart() { + Block beneath = getBlockBeneath(player.getLocation().clone()); + double maxHeight = getMaxHeight(); + + return isEarthbendable(player, beneath) && !isMetal(beneath) && beneath.getLocation().distanceSquared(player.getLocation()) <= maxHeight * maxHeight && !EarthAbility.getMovedEarth().containsKey(beneath); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Earth.EarthSurf.Cooldown.Cooldown"); + minimumCooldown = config.getLong("Abilities.Earth.EarthSurf.Cooldown.MinimumCooldown"); + duration = config.getLong("Abilities.Earth.EarthSurf.Duration.Duration"); + cooldownEnabled = config.getBoolean("Abilities.Earth.EarthSurf.Cooldown.Enabled"); + durationEnabled = config.getBoolean("Abilities.Earth.EarthSurf.Duration.Enabled"); + removeOnAnyDamage = config.getBoolean("Abilities.Earth.EarthSurf.RemoveOnAnyDamage"); + speed = config.getDouble("Abilities.Earth.EarthSurf.Speed"); + springStiffness = config.getDouble("Abilities.Earth.EarthSurf.SpringStiffness"); + + int smootherSize = config.getInt("Abilities.Earth.EarthSurf.HeightTolerance"); + this.heightSmoother = new DoubleSmoother(Math.max(smootherSize, 1)); + + if (config.getBoolean("Abilities.Earth.EarthSurf.RelaxedCollisions")) { + this.collisionDetector = new RelaxedCollisionDetector(); + } + + if (!config.getBoolean("Abilities.Earth.EarthSurf.Cooldown.Scaled")) { + minimumCooldown = cooldown; + } + } + + @Override + public void progress() { + if (shouldRemove()) { + remove(); + return; + } + + this.player.setFlying(false); + + if (!collisionDetector.isColliding(player) && player.getHealth() >= prevHealth) { + movePlayer(); + + if (removeOnAnyDamage) { + prevHealth = player.getHealth(); + } + } else { + remove(); + } + } + + private boolean shouldRemove() { + if (player == null || player.isDead() || !player.isOnline()) return true; + if (!bPlayer.canBendIgnoreCooldowns(this)) return true; + if (!isEarthbendable(player, getBlockBeneath(player.getLocation().clone()))) return true; + if (durationEnabled && System.currentTimeMillis() > getStartTime() + duration) return true; + + return player.isSneaking(); + } + + private void movePlayer() { + location = player.getEyeLocation().clone(); + location.setPitch(0); + Vector direction = location.getDirection().normalize(); + + // How far the player is above the ground. + double height = getPlayerDistance(); + double maxHeight = getMaxHeight(); + double smoothedHeight = heightSmoother.add(height); + + // Destroy ability if player gets too far from ground. + if (smoothedHeight > maxHeight) { + remove(); + return; + } + + // Calculate the spring force to push the player back to the target height. + double displacement = height - TARGET_HEIGHT; + double force = -springStiffness * displacement; + + double maxForce = 0.5; + if (Math.abs(force) > maxForce) { + // Cap the force to maxForce so the player isn't instantly pulled to the ground. + force = force / Math.abs(force) * maxForce; + } + + Vector velocity = direction.clone().multiply(speed).setY(force); + + rideWave(); + + player.setVelocity(velocity); + player.setFallDistance(0); + } + + private double getMaxHeight() { + return TARGET_HEIGHT + 2.0; + } + + private double getPlayerDistance() { + Location l = player.getLocation().clone(); + while (true) { + if (l.getBlockY() <= l.getWorld().getMinHeight()) break; + if (ElementalAbility.isAir(l.getBlock().getType()) && ridingBlocks.contains(l.getBlock())) break; + if (GeneralMethods.isSolid(l.getBlock())) break; + + l.add(0, -0.1, 0); + } + return player.getLocation().getY() - l.getY(); + } + + private Block getBlockBeneath(Location l) { + while (l.getBlockY() > l.getWorld().getMinHeight() && MaterialUtil.isTransparent(l.getBlock())) { + l.add(0, -0.5, 0); + } + return l.getBlock(); + } + + private void rideWave() { + for (int i = 0; i < 3; i++) { + Location loc = location.clone(); + if (i < 2) + loc.add(getSideDirection(i)); + + //Player Positioning + double distOffset = 2.5; + Location bL = loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()); + while (!ElementalAbility.isAir(loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()).getBlock().getType())) { + loc.add(0, 0.1, 0); + } + + Block beneath = getBlockBeneath(loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld())); + if (isEarthbendable(player, beneath) && beneath != null && !EarthAbility.getMovedEarth().containsKey(beneath)) { + Block block = loc.clone().add(0, -3.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset - 0.5)).toLocation(player.getWorld()).getBlock(); + Location temp = loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()); + + if (RegionProtection.isRegionProtected(this, block.getLocation())) { + continue; + } + // Don't render blocks above the player because it looks bad. + // TODO: Change this check to see if it's a reachable position instead. + if (block.getLocation().getY() > this.player.getLocation().getY()) { + continue; + } + + if (DensityShift.isPassiveSand(block)) { + DensityShift.revertSand(block); + } + + if (!GeneralMethods.isSolid(block.getLocation().add(0, 1, 0).getBlock()) && !ElementalAbility.isAir(block.getLocation().add(0, 1, 0).getBlock().getType())) { + if (DensityShift.isPassiveSand(block.getRelative(BlockFace.UP))) { + DensityShift.revertSand(block.getRelative(BlockFace.UP)); + } + + new TempBlock(block.getRelative(BlockFace.UP), Material.AIR.createBlockData()); + } + + if (GeneralMethods.isSolid(block)) { + ridingBlocks.add(block); + new RegenTempBlock(block, Material.AIR, Material.AIR.createBlockData(), 1000L, true, ridingBlocks::remove); + } else { + new RegenTempBlock(block, Material.AIR, Material.AIR.createBlockData(), 1000L); + } + + new TempFallingBlock(temp, getBlockBeneath(bL).getBlockData(), new Vector(0, 0.25, 0), this, true); + + for (Entity e : GeneralMethods.getEntitiesAroundPoint(loc.clone().add(0, -2.9, 0).toVector().add(location.clone().getDirection().multiply(distOffset)).toLocation(player.getWorld()), 1.5D)) { + if (e instanceof LivingEntity && e.getEntityId() != player.getEntityId()) { + e.setVelocity(new Vector(0, 0.3, 0)); + } + } + } + } + } + + private Vector getSideDirection(int side) { + Vector direction = location.clone().getDirection().normalize(); + switch (side) { + case 0: // RIGHT + return new Vector(-direction.getZ(), 0.0, direction.getX()).normalize(); + case 1: // LEFT + return new Vector(direction.getZ(), 0.0, -direction.getX()).normalize(); + default: + break; + } + + return null; + } + + @Override + public void remove() { + this.flightHandler.removeInstance(player, this.getName()); + + if (cooldownEnabled && player.isOnline()) { + long scaledCooldown = cooldown; + + if (durationEnabled && duration > 0) { + double t = Math.min((System.currentTimeMillis() - this.getStartTime()) / (double) duration, 1.0); + scaledCooldown = Math.max((long) (cooldown * t), minimumCooldown); + } + + bPlayer.addCooldown(this, scaledCooldown); + } + + super.remove(); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getName() { + return "EarthSurf"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthSurf.Description"); + } + + public static double getTargetHeight() { + return TARGET_HEIGHT; + } + + public void setLocation(Location location) { + this.location = location; + } + + public double getPrevHealth() { + return prevHealth; + } + + public void setPrevHealth(double prevHealth) { + this.prevHealth = prevHealth; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public long getMinimumCooldown() { + return minimumCooldown; + } + + public void setMinimumCooldown(long minimumCooldown) { + this.minimumCooldown = minimumCooldown; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public boolean isCooldownEnabled() { + return cooldownEnabled; + } + + public void setCooldownEnabled(boolean cooldownEnabled) { + this.cooldownEnabled = cooldownEnabled; + } + + public boolean isDurationEnabled() { + return durationEnabled; + } + + public void setDurationEnabled(boolean durationEnabled) { + this.durationEnabled = durationEnabled; + } + + public boolean isRemoveOnAnyDamage() { + return removeOnAnyDamage; + } + + public void setRemoveOnAnyDamage(boolean removeOnAnyDamage) { + this.removeOnAnyDamage = removeOnAnyDamage; + } + + public double getSpeed() { + return speed; + } + + public void setSpeed(double speed) { + this.speed = speed; + } + + public double getSpringStiffness() { + return springStiffness; + } + + public void setSpringStiffness(double springStiffness) { + this.springStiffness = springStiffness; + } + + public Set getRidingBlocks() { + return ridingBlocks; + } + + public CollisionDetector getCollisionDetector() { + return collisionDetector; + } + + public void setCollisionDetector(CollisionDetector collisionDetector) { + this.collisionDetector = collisionDetector; + } + + public DoubleSmoother getHeightSmoother() { + return heightSmoother; + } + + public void setHeightSmoother(DoubleSmoother heightSmoother) { + this.heightSmoother = heightSmoother; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + return config.getBoolean("Abilities.Earth.EarthSurf.Enabled"); + } + + private interface CollisionDetector { + boolean isColliding(Player player); + } + + private abstract static class AbstractCollisionDetector implements CollisionDetector { + protected boolean isCollision(Location location) { + Block block = location.getBlock(); + return !MaterialUtil.isTransparent(block) || block.isLiquid() || block.getType().isSolid(); + } + } + + private class DefaultCollisionDetector extends AbstractCollisionDetector { + @Override + public boolean isColliding(Player player) { + // The location in front of the player, where the player will be in one second. + Location front = player.getEyeLocation().clone(); + front.setPitch(0); + + Vector direction = front.getDirection().clone().setY(0).normalize(); + double playerSpeed = player.getVelocity().clone().setY(0).length(); + + front.add(direction.clone().multiply(Math.max(speed, playerSpeed))); + + for (int i = 0; i < 3; ++i) { + Location location = front.clone().add(0, -i, 0); + if (isCollision(location)) { + return true; + } + } + + return false; + } + } + + private class RelaxedCollisionDetector extends AbstractCollisionDetector { + @Override + public boolean isColliding(Player player) { + // The location in front of the player, where the player will be in one second. + Location front = player.getEyeLocation().clone().subtract(0.0, 0.5, 0.0); + front.setPitch(0); + + Vector direction = front.getDirection().clone().setY(0).normalize(); + double playerSpeed = player.getVelocity().clone().setY(0).length(); + + front.add(direction.clone().multiply(Math.max(speed, playerSpeed))); + + return isCollision(front); + } + } + + private static class DoubleSmoother { + private final double[] values; + private final int size; + private int index; + + public DoubleSmoother(int size) { + this.size = size; + this.index = 0; + + values = new double[size]; + } + + public double add(double value) { + values[index] = value; + index = (index + 1) % size; + return get(); + } + + public double get() { + return Arrays.stream(this.values).sum() / this.size; + } + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/Fissure.java b/src/com/jedk1/jedcore/ability/earthbending/Fissure.java index 7f947a5..c3bbc98 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/Fissure.java +++ b/src/com/jedk1/jedcore/ability/earthbending/Fissure.java @@ -2,7 +2,6 @@ import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; -import com.jedk1.jedcore.util.RegenTempBlock; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.EarthAbility; @@ -13,7 +12,6 @@ import com.projectkorra.projectkorra.util.Information; import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -30,412 +28,412 @@ public class Fissure extends LavaAbility implements AddonAbility { - @Attribute(Attribute.RANGE) - private int slapRange; - @Attribute(Attribute.WIDTH) - private int maxWidth; - private long slapDelay; - @Attribute(Attribute.DURATION) - private long duration; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - - private Location location; - private Vector direction; - private Vector blockDirection; - private long time; - private long step; - private int slap; - private int width; - private boolean progressed; - - static Random rand = new Random(); - - private final List centerSlap = new ArrayList<>(); - private final List blocks = new ArrayList<>(); - private final List tempblocks = new ArrayList<>(); - - public Fissure(Player player) { - super(player); - - if (!bPlayer.canBend(this) || hasAbility(player, Fissure.class) || !bPlayer.canLavabend()) { - return; - } - - setFields(); - time = System.currentTimeMillis(); - step = System.currentTimeMillis() + slapDelay; - location = player.getLocation().clone(); - location.setPitch(0); - direction = location.getDirection(); - blockDirection = this.direction.clone().setX(Math.round(this.direction.getX())); - blockDirection = blockDirection.setZ(Math.round(direction.getZ())); - if (prepareLine()) { - start(); - if (!isRemoved()) { - bPlayer.addCooldown(this); - } - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - slapRange = config.getInt("Abilities.Earth.Fissure.SlapRange"); - maxWidth = config.getInt("Abilities.Earth.Fissure.MaxWidth"); - slapDelay = config.getInt("Abilities.Earth.Fissure.SlapDelay"); - duration = config.getInt("Abilities.Earth.Fissure.Duration"); - cooldown = config.getInt("Abilities.Earth.Fissure.Cooldown"); - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - if (System.currentTimeMillis() > step && slap <= centerSlap.size()) { - time = System.currentTimeMillis(); - step = System.currentTimeMillis() + slapDelay; - slapCenter(); - slap++; - } - if (System.currentTimeMillis() > time + duration) { - remove(); - } - } - - private boolean prepareLine() { - direction = player.getEyeLocation().getDirection().setY(0).normalize(); - blockDirection = this.direction.clone().setX(Math.round(this.direction.getX())); - blockDirection = blockDirection.setZ(Math.round(direction.getZ())); - Location origin = player.getLocation().add(0, -1, 0).add(blockDirection.multiply(2)); - if (isEarthbendable(player, origin.getBlock())) { - BlockIterator bi = new BlockIterator(player.getWorld(), origin.toVector(), direction, 0, slapRange); - - while (bi.hasNext()) { - Block b = bi.next(); - - if (b.getY() > 1 && b.getY() < 255 && !RegionProtection.isRegionProtected(this, b.getLocation())) { - if (EarthAbility.getMovedEarth().containsKey(b)){ - Information info = EarthAbility.getMovedEarth().get(b); - if(!info.getBlock().equals(b)) { - continue; - } - } - - while (!isEarthbendable(player, b)) { - b = b.getRelative(BlockFace.DOWN); - if (b.getY() < b.getWorld().getMinHeight() || b.getY() > b.getWorld().getMaxHeight()) { - break; - } - if (isEarthbendable(player, b)) { - break; - } - } - - while (!isTransparent(b.getRelative(BlockFace.UP))) { - b = b.getRelative(BlockFace.UP); - if (b.getY() < b.getWorld().getMinHeight() || b.getY() > b.getWorld().getMaxHeight()) { - break; - } - if (isEarthbendable(player, b.getRelative(BlockFace.UP))) { - break; - } - } - - if (isEarthbendable(player, b)) { - centerSlap.add(b.getLocation()); - } else { - break; - } - } - } - return true; - } - return false; - } - - private void slapCenter() { - for (Location location : centerSlap) { - if (centerSlap.indexOf(location) == slap) { - addTempBlock(location.getBlock(), Material.LAVA); - } - } - if (slap >= centerSlap.size()) { - progressed = true; - } - } - - public static void performAction(Player player) { - if (hasAbility(player, Fissure.class)) { - getAbility(player, Fissure.class).performAction(); - } - } - - private void performAction() { - if (width < maxWidth) { - expandFissure(); - } else if (blocks.contains(player.getTargetBlock(null, 10))) { - forceRevert(); - } - } - - private void expandFissure() { - if (progressed && width <= maxWidth) { - width++; - for (Location location : centerSlap) { - Block left = location.getBlock().getRelative(getLeftBlockFace(GeneralMethods.getCardinalDirection(blockDirection)), width); - expand(left); - - Block right = location.getBlock().getRelative(getLeftBlockFace(GeneralMethods.getCardinalDirection(blockDirection)).getOppositeFace(), width); - expand(right); - } - } - Collections.reverse(blocks); - } - - private void expand(Block block) { - if (block != null && block.getY() > 1 && block.getY() < 255 && !RegionProtection.isRegionProtected(this, block.getLocation())) { - if (EarthAbility.getMovedEarth().containsKey(block)){ - Information info = EarthAbility.getMovedEarth().get(block); - if(!info.getBlock().equals(block)) { - return; - } - } - - while (!isEarthbendable(player, block)) { - block = block.getRelative(BlockFace.DOWN); - if (block.getY() < 1 || block.getY() > 255) { - break; - } - if (isEarthbendable(player, block)) { - break; - } - } - - while (!isTransparent(player, block.getRelative(BlockFace.UP))) { - block = block.getRelative(BlockFace.UP); - if (block.getY() < 1 || block.getY() > 255) { - break; - } - if (isEarthbendable(player, block.getRelative(BlockFace.UP))) { - break; - } - } - - if (isEarthbendable(player, block)) { - addTempBlock(block, Material.LAVA); - } - } - } - - private void addTempBlock(Block block, Material material) { - ParticleEffect.LAVA.display(block.getLocation(), 0, 0, 0, 0, 1); - playEarthbendingSound(block.getLocation()); - if (DensityShift.isPassiveSand(block)) { + @Attribute(Attribute.RANGE) + private int slapRange; + @Attribute(Attribute.WIDTH) + private int maxWidth; + private long slapDelay; + @Attribute(Attribute.DURATION) + private long duration; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + + private Location location; + private Vector direction; + private Vector blockDirection; + private long time; + private long step; + private int slap; + private int width; + private boolean progressed; + + static Random rand = new Random(); + + private final List centerSlap = new ArrayList<>(); + private final List blocks = new ArrayList<>(); + private final List tempblocks = new ArrayList<>(); + + public Fissure(Player player) { + super(player); + + if (!bPlayer.canBend(this) || hasAbility(player, Fissure.class) || !bPlayer.canLavabend()) { + return; + } + + setFields(); + time = System.currentTimeMillis(); + step = System.currentTimeMillis() + slapDelay; + location = player.getLocation().clone(); + location.setPitch(0); + direction = location.getDirection(); + blockDirection = this.direction.clone().setX(Math.round(this.direction.getX())); + blockDirection = blockDirection.setZ(Math.round(direction.getZ())); + if (prepareLine()) { + start(); + if (!isRemoved()) { + bPlayer.addCooldown(this); + } + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + slapRange = config.getInt("Abilities.Earth.Fissure.SlapRange"); + maxWidth = config.getInt("Abilities.Earth.Fissure.MaxWidth"); + slapDelay = config.getInt("Abilities.Earth.Fissure.SlapDelay"); + duration = config.getInt("Abilities.Earth.Fissure.Duration"); + cooldown = config.getInt("Abilities.Earth.Fissure.Cooldown"); + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + if (System.currentTimeMillis() > step && slap <= centerSlap.size()) { + time = System.currentTimeMillis(); + step = System.currentTimeMillis() + slapDelay; + slapCenter(); + slap++; + } + if (System.currentTimeMillis() > time + duration) { + remove(); + } + } + + private boolean prepareLine() { + direction = player.getEyeLocation().getDirection().setY(0).normalize(); + blockDirection = this.direction.clone().setX(Math.round(this.direction.getX())); + blockDirection = blockDirection.setZ(Math.round(direction.getZ())); + Location origin = player.getLocation().add(0, -1, 0).add(blockDirection.multiply(2)); + if (isEarthbendable(player, origin.getBlock())) { + BlockIterator bi = new BlockIterator(player.getWorld(), origin.toVector(), direction, 0, slapRange); + + while (bi.hasNext()) { + Block b = bi.next(); + + if (b.getY() > b.getWorld().getMinHeight() && b.getY() < b.getWorld().getMaxHeight() && !RegionProtection.isRegionProtected(this, b.getLocation())) { + if (EarthAbility.getMovedEarth().containsKey(b)){ + Information info = EarthAbility.getMovedEarth().get(b); + if(!info.getBlock().equals(b)) { + continue; + } + } + + while (!isEarthbendable(player, b)) { + b = b.getRelative(BlockFace.DOWN); + if (b.getY() < b.getWorld().getMinHeight() || b.getY() > b.getWorld().getMaxHeight()) { + break; + } + if (isEarthbendable(player, b)) { + break; + } + } + + while (!isTransparent(b.getRelative(BlockFace.UP))) { + b = b.getRelative(BlockFace.UP); + if (b.getY() < b.getWorld().getMinHeight() || b.getY() > b.getWorld().getMaxHeight()) { + break; + } + if (isEarthbendable(player, b.getRelative(BlockFace.UP))) { + break; + } + } + + if (isEarthbendable(player, b)) { + centerSlap.add(b.getLocation()); + } else { + break; + } + } + } + return true; + } + return false; + } + + private void slapCenter() { + for (Location location : centerSlap) { + if (centerSlap.indexOf(location) == slap) { + addTempBlock(location.getBlock(), Material.LAVA); + } + } + if (slap >= centerSlap.size()) { + progressed = true; + } + } + + public static void performAction(Player player) { + if (hasAbility(player, Fissure.class)) { + getAbility(player, Fissure.class).performAction(); + } + } + + private void performAction() { + if (width < maxWidth) { + expandFissure(); + } else if (blocks.contains(player.getTargetBlock(null, 10))) { + forceRevert(); + } + } + + private void expandFissure() { + if (progressed && width <= maxWidth) { + width++; + for (Location location : centerSlap) { + Block left = location.getBlock().getRelative(getLeftBlockFace(GeneralMethods.getCardinalDirection(blockDirection)), width); + expand(left); + + Block right = location.getBlock().getRelative(getLeftBlockFace(GeneralMethods.getCardinalDirection(blockDirection)).getOppositeFace(), width); + expand(right); + } + } + Collections.reverse(blocks); + } + + private void expand(Block block) { + if (block != null && block.getY() > block.getWorld().getMinHeight() && block.getY() < block.getWorld().getMaxHeight() && !RegionProtection.isRegionProtected(this, block.getLocation())) { + if (EarthAbility.getMovedEarth().containsKey(block)){ + Information info = EarthAbility.getMovedEarth().get(block); + if(!info.getBlock().equals(block)) { + return; + } + } + + while (!isEarthbendable(player, block)) { + block = block.getRelative(BlockFace.DOWN); + if (block.getY() < block.getWorld().getMinHeight() || block.getY() > block.getWorld().getMaxHeight()) { + break; + } + if (isEarthbendable(player, block)) { + break; + } + } + + while (!isTransparent(player, block.getRelative(BlockFace.UP))) { + block = block.getRelative(BlockFace.UP); + if (block.getY() < block.getWorld().getMinHeight() || block.getY() > block.getWorld().getMaxHeight()) { + break; + } + if (isEarthbendable(player, block.getRelative(BlockFace.UP))) { + break; + } + } + + if (isEarthbendable(player, block)) { + addTempBlock(block, Material.LAVA); + } + } + } + + private void addTempBlock(Block block, Material material) { + ParticleEffect.LAVA.display(block.getLocation(), 0, 0, 0, 0, 1); + playEarthbendingSound(block.getLocation()); + if (DensityShift.isPassiveSand(block)) { DensityShift.revertSand(block); - } - tempblocks.add(new TempBlock(block, material.createBlockData(), this)); - blocks.add(block); - } - - public BlockFace getLeftBlockFace(BlockFace forward) { - switch (forward) { - case NORTH: - return BlockFace.WEST; - case SOUTH: - return BlockFace.EAST; - case WEST: - return BlockFace.SOUTH; - case EAST: - return BlockFace.NORTH; - case NORTH_WEST: - return BlockFace.SOUTH_WEST; - case NORTH_EAST: - return BlockFace.NORTH_WEST; - case SOUTH_WEST: - return BlockFace.SOUTH_EAST; - case SOUTH_EAST: - return BlockFace.NORTH_EAST; - default: - return BlockFace.NORTH; - } - } - - private void forceRevert() { - coolLava(); - } - - private void coolLava() { - tempblocks.forEach(TempBlock::revertBlock); - for (Block block : blocks) { - new TempBlock(block, Material.STONE.createBlockData(), 500 + (long) rand.nextInt((int) 1000)); - } - blocks.clear(); - tempblocks.clear(); - } - - @Override - public void remove() { - coolLava(); - super.remove(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public String getName() { - return "Fissure"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.Fissure.Description"); - } - - public int getSlapRange() { - return slapRange; - } - - public void setSlapRange(int slapRange) { - this.slapRange = slapRange; - } - - public int getMaxWidth() { - return maxWidth; - } - - public void setMaxWidth(int maxWidth) { - this.maxWidth = maxWidth; - } - - public long getSlapDelay() { - return slapDelay; - } - - public void setSlapDelay(long slapDelay) { - this.slapDelay = slapDelay; - } - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public void setLocation(Location location) { - this.location = location; - } - - public Vector getDirection() { - return direction; - } - - public void setDirection(Vector direction) { - this.direction = direction; - } - - public Vector getBlockDirection() { - return blockDirection; - } - - public void setBlockDirection(Vector blockDirection) { - this.blockDirection = blockDirection; - } - - public long getTime() { - return time; - } - - public void setTime(long time) { - this.time = time; - } - - public long getStep() { - return step; - } - - public void setStep(long step) { - this.step = step; - } - - public int getSlap() { - return slap; - } - - public void setSlap(int slap) { - this.slap = slap; - } - - public int getWidth() { - return width; - } - - public void setWidth(int width) { - this.width = width; - } - - public boolean isProgressed() { - return progressed; - } - - public void setProgressed(boolean progressed) { - this.progressed = progressed; - } - - public List getCenterSlap() { - return centerSlap; - } + } + tempblocks.add(new TempBlock(block, material.createBlockData(), this)); + blocks.add(block); + } + + public BlockFace getLeftBlockFace(BlockFace forward) { + switch (forward) { + case NORTH: + return BlockFace.WEST; + case SOUTH: + return BlockFace.EAST; + case WEST: + return BlockFace.SOUTH; + case EAST: + return BlockFace.NORTH; + case NORTH_WEST: + return BlockFace.SOUTH_WEST; + case NORTH_EAST: + return BlockFace.NORTH_WEST; + case SOUTH_WEST: + return BlockFace.SOUTH_EAST; + case SOUTH_EAST: + return BlockFace.NORTH_EAST; + default: + return BlockFace.NORTH; + } + } + + private void forceRevert() { + coolLava(); + } + + private void coolLava() { + tempblocks.forEach(TempBlock::revertBlock); + for (Block block : blocks) { + new TempBlock(block, Material.STONE.createBlockData(), 500 + (long) rand.nextInt((int) 1000)); + } + blocks.clear(); + tempblocks.clear(); + } + + @Override + public void remove() { + coolLava(); + super.remove(); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getName() { + return "Fissure"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.Fissure.Description"); + } + + public int getSlapRange() { + return slapRange; + } + + public void setSlapRange(int slapRange) { + this.slapRange = slapRange; + } + + public int getMaxWidth() { + return maxWidth; + } + + public void setMaxWidth(int maxWidth) { + this.maxWidth = maxWidth; + } + + public long getSlapDelay() { + return slapDelay; + } + + public void setSlapDelay(long slapDelay) { + this.slapDelay = slapDelay; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public void setLocation(Location location) { + this.location = location; + } + + public Vector getDirection() { + return direction; + } + + public void setDirection(Vector direction) { + this.direction = direction; + } + + public Vector getBlockDirection() { + return blockDirection; + } + + public void setBlockDirection(Vector blockDirection) { + this.blockDirection = blockDirection; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public long getStep() { + return step; + } + + public void setStep(long step) { + this.step = step; + } + + public int getSlap() { + return slap; + } + + public void setSlap(int slap) { + this.slap = slap; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public boolean isProgressed() { + return progressed; + } + + public void setProgressed(boolean progressed) { + this.progressed = progressed; + } + + public List getCenterSlap() { + return centerSlap; + } - public List getBlocks() { - return blocks; - } + public List getBlocks() { + return blocks; + } - @Override - public void load() {} + @Override + public void load() {} - @Override - public void stop() {} + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.Fissure.Enabled"); - } + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.Fissure.Enabled"); + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/LavaDisc.java b/src/com/jedk1/jedcore/ability/earthbending/LavaDisc.java index 65cdf08..5d64f5f 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/LavaDisc.java +++ b/src/com/jedk1/jedcore/ability/earthbending/LavaDisc.java @@ -1,16 +1,19 @@ package com.jedk1.jedcore.ability.earthbending; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - +import com.jedk1.jedcore.JCMethods; +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.policies.removal.*; -import com.projectkorra.projectkorra.ability.CoreAbility; -import com.projectkorra.projectkorra.ability.ElementalAbility; +import com.jedk1.jedcore.util.RegenTempBlock; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.*; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.earthbending.passive.DensityShift; +import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.region.RegionProtection; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.TempBlock; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Material; @@ -23,531 +26,530 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import com.jedk1.jedcore.JCMethods; -import com.jedk1.jedcore.JedCore; -import com.jedk1.jedcore.util.RegenTempBlock; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.LavaAbility; -import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; -import com.projectkorra.projectkorra.util.TempBlock; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class LavaDisc extends LavaAbility implements AddonAbility { - private Location location; - private int recallCount; - - private long time; - - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.DURATION) - private long duration; - private int recallLimit; - private boolean trailFlow; - - private CompositeRemovalPolicy removalPolicy; - private DiscRenderer discRenderer; - private State state; - private final Set trailBlocks = new HashSet<>(); - - public LavaDisc(Player player) { - super(player); - - if (!bPlayer.canBend(this) || !bPlayer.canLavabend()) { - return; - } - - // Allow new LavaDisc if all existing instances for that player are in CleanupState. - for (LavaDisc disc : CoreAbility.getAbilities(player, LavaDisc.class)) { - if (!(disc.state instanceof CleanupState)) { - return; - } - } - - state = new HoldState(); - time = System.currentTimeMillis(); - discRenderer = new DiscRenderer(this.player); - - setFields(); - - if (prepare()) { - start(); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - damage = config.getDouble("Abilities.Earth.LavaDisc.Damage"); - cooldown = config.getLong("Abilities.Earth.LavaDisc.Cooldown"); - duration = config.getLong("Abilities.Earth.LavaDisc.Duration"); - recallLimit = config.getInt("Abilities.Earth.LavaDisc.RecallLimit") - 1; - trailFlow = config.getBoolean("Abilities.Earth.LavaDisc.Destroy.TrailFlow"); - - this.removalPolicy = new CompositeRemovalPolicy(this, - new CannotBendRemovalPolicy(this.bPlayer, this, true, true), - new IsOfflineRemovalPolicy(this.player), - new IsDeadRemovalPolicy(this.player), - new SwappedSlotsRemovalPolicy<>(bPlayer, LavaDisc.class) - ); - - this.removalPolicy.load(config); - } - - private boolean prepare() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - long sourceRegen = config.getLong("Abilities.Earth.LavaDisc.Source.RegenTime"); - boolean lavaOnly = config.getBoolean("Abilities.Earth.LavaDisc.Source.LavaOnly"); - double sourceRange = config.getDouble("Abilities.Earth.LavaDisc.Source.Range"); - - if (getLavaSourceBlock(player, sourceRange) != null) { - Block block = getLavaSourceBlock(player, sourceRange); - new RegenTempBlock(block, Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(4)), sourceRegen); - return true; - } else if (getEarthSourceBlock(sourceRange) != null) { - if (lavaOnly) - return false; - Block block = getEarthSourceBlock(sourceRange); - new RegenTempBlock(block, Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(4)), sourceRegen); - return true; - } - - return false; - } - - @Override - public void progress() { - if (this.removalPolicy.shouldRemove()) { - if (!player.isOnline()) { - // Revert all of the lava blocks if the player goes offline. - for (Block block : trailBlocks) { - RegenTempBlock.revert(block); - } - bPlayer.addCooldown(this); - remove(); - return; - } else if (!(state instanceof CleanupState)) { - state = new CleanupState(); - } - } - - if (!hasAbility(player, LavaDisc.class)) { - return; - } - - state.update(); - } - - public static boolean canFlowFrom(Block from) { - Material type = from.getType(); - if (type != Material.LAVA && !ElementalAbility.isAir(type)) { - return true; - } - - for (LavaDisc disc : CoreAbility.getAbilities(LavaDisc.class)) { - if (disc.trailFlow) continue; - - if (disc.trailBlocks.contains(from)) { - return false; - } - } - - return true; - } - - private boolean isLocationSafe() { - if (!isLocationSafe(location)) { - return false; - } - - Block block = location.getBlock(); - - return isTransparent(block); - } - - private boolean isLocationSafe(Location location) { - if (location == null || location.getWorld() == null) { - return false; - } - - return location.getY() >= location.getWorld().getMinHeight() && location.getY() <= (location.getWorld().getMaxHeight() - 1); - } - - private void doDamage(Entity entity) { - DamageHandler.damageEntity(entity, damage, this); - entity.setFireTicks(20); - new FireDamageTimer(entity, player, this); - ParticleEffect.LAVA.display(entity.getLocation(), 15, Math.random(), Math.random(), Math.random(), 0.1); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public String getName() { - return "LavaDisc"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.LavaDisc.Description"); - } - - public void setLocation(Location location) { - this.location = location; - } - - public int getRecallCount() { - return recallCount; - } - - public void setRecallCount(int recallCount) { - this.recallCount = recallCount; - } - - public long getTime() { - return time; - } - - public void setTime(long time) { - this.time = time; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - public int getRecallLimit() { - return recallLimit; - } - - public void setRecallLimit(int recallLimit) { - this.recallLimit = recallLimit; - } - - public boolean isTrailFlow() { - return trailFlow; - } - - public void setTrailFlow(boolean trailFlow) { - this.trailFlow = trailFlow; - } - - public DiscRenderer getDiscRenderer() { - return discRenderer; - } - - public void setDiscRenderer(DiscRenderer discRenderer) { - this.discRenderer = discRenderer; - } - - public State getState() { - return state; - } - - public void setState(State state) { - this.state = state; - } - - public Set getTrailBlocks() { - return trailBlocks; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.LavaDisc.Enabled"); - } - - private interface State { - void update(); - } - - // Renders the particles showing that the player is holding lava. - // Transitions to ForwardTravelState when the player stops sneaking. - private class HoldState implements State { - @Override - public void update() { - location = player.getEyeLocation(); - Vector dV = location.getDirection().normalize(); - location.add(new Vector(dV.getX() * 3, dV.getY() * 3, dV.getZ() * 3)); - - dV = dV.multiply(0.1); - - while (!isLocationSafe() && isLocationSafe(player.getLocation())) { - location.subtract(dV); - if (location.distanceSquared(player.getEyeLocation()) > (3 * 3)) { - break; - } - } - - discRenderer.render(location, false); - - location.setPitch(0); - - if (!player.isSneaking()) { - time = System.currentTimeMillis(); - state = new ForwardTravelState(location.getDirection().normalize()); - } - } - } - - private abstract class TravelState implements State { - private final boolean passHit; - - protected Vector direction; - protected boolean hasHit; - - public TravelState() { - this(player.getEyeLocation().getDirection()); - } - - public TravelState(Vector direction) { - this.direction = direction; - - ConfigurationSection config = JedCoreConfig.getConfig(player); - - passHit = config.getBoolean("Abilities.Earth.LavaDisc.ContinueAfterEntityHit"); - } - - protected void move() { - for (int i = 0; i < 5; i++) { - location = location.add(direction.clone().multiply(0.15)); - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.0D)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) { - doDamage(entity); - if (!passHit) { - hasHit = true; - return; - } - } - } - } - } - } - - // Moves the disc forward. Makes the disc destroy blocks if enabled. - // Transitions to ReverseTravelState if the player starts sneaking and can recall. - // Transitions to CleanupState if it times out or hits an entity. - private class ForwardTravelState extends TravelState { - public ForwardTravelState() { - this(player.getEyeLocation().getDirection()); - } - - public ForwardTravelState(Vector direction) { - super(direction); - } - - @Override - public void update() { - if (!isLocationSafe() || System.currentTimeMillis() > time + duration) { - state = new CleanupState(); - return; - } - - if (player.isSneaking() && recallCount <= recallLimit) { - state = new ReverseTravelState(); - return; - } - - alterPitch(); - move(); - discRenderer.render(location, true); - - if (hasHit) { - state = new CleanupState(); - } - } - - private void alterPitch() { - Location loc = player.getLocation().clone(); - - if (loc.getPitch() < -20) - loc.setPitch(-20); - if (loc.getPitch() > 20) - loc.setPitch(20); - - direction = loc.getDirection().normalize(); - } - } - - // Returns the disc to the player. - // Transitions to ForwardTravelState if the player stops sneaking. - // Transitions to HoldState if the disc gets close enough to the player. - private class ReverseTravelState extends TravelState { - @Override - public void update() { - if (!player.isSneaking()) { - state = new ForwardTravelState(); - return; - } - - Location loc = player.getEyeLocation(); - Vector dV = loc.getDirection().normalize(); - loc.add(new Vector(dV.getX() * 3, dV.getY() * 3, dV.getZ() * 3)); - - Vector vector = loc.toVector().subtract(location.toVector()); - direction = loc.setDirection(vector).getDirection().normalize(); - - move(); - discRenderer.render(location, true); - - double distanceAway = location.distance(loc); - if (distanceAway < 0.5) { - recallCount++; - // Player is holding the disc when it gets close enough to them. - state = new HoldState(); - } - } - } - - // Waits for the RegenTempBlocks to revert. - // This exists so the instance stays alive and block flow events can stop the lava from flowing. - private class CleanupState implements State { - private final long startTime; - private final long regenTime; - - public CleanupState() { - this.startTime = System.currentTimeMillis(); - - ConfigurationSection config = JedCoreConfig.getConfig(player); - - regenTime = config.getLong("Abilities.Earth.LavaDisc.Destroy.RegenTime"); - bPlayer.addCooldown(LavaDisc.this); - } - - @Override - public void update() { - if (System.currentTimeMillis() >= startTime + regenTime || trailBlocks.isEmpty()) { - remove(); - } - } - } - - private class DiscRenderer { - private final Player player; - private int angle; - - private final boolean damageBlocks; - private final List meltable; - private final long regenTime; - private final boolean lavaTrail; - - private final int particles; - - - public DiscRenderer(Player player) { - this.player = player; - this.angle = 0; - - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - damageBlocks = config.getBoolean("Abilities.Earth.LavaDisc.Destroy.BlockDamage"); - meltable = config.getStringList("Abilities.Earth.LavaDisc.Destroy.AdditionalMeltableBlocks"); - regenTime = config.getLong("Abilities.Earth.LavaDisc.Destroy.RegenTime"); - lavaTrail = config.getBoolean("Abilities.Earth.LavaDisc.Destroy.LavaTrail"); - particles = config.getInt("Abilities.Earth.LavaDisc.Particles"); - } - - void render(Location location, boolean largeLava) { - if (largeLava) - ParticleEffect.LAVA.display(location, particles * 2, Math.random(), Math.random(), Math.random(), 0.1); - else - ParticleEffect.LAVA.display(location, 1, Math.random(), Math.random(), Math.random(), 0.1); - - angle += 1; - if (angle > 360) - angle = 0; - - for (Location l : JCMethods.getCirclePoints(location, 20, 1, angle)) { - ParticleEffect.REDSTONE.display(l, 0, 196, 93, 0, 0.005F, new Particle.DustOptions(Color.fromRGB(196, 93, 0), 1)); - if (largeLava && damageBlocks) - damageBlocks(l); - } - - for (Location l : JCMethods.getCirclePoints(location, 10, 0.5, angle)) { - ParticleEffect.FLAME.display(l, 1, 0, 0, 0, 0.01); - ParticleEffect.SMOKE_NORMAL.display(l, 1, 0, 0, 0, 0.05); - if (largeLava && damageBlocks) - damageBlocks(l); - } - } - - private void damageBlocks(Location l) { - if (!RegionProtection.isRegionProtected(player, l, LavaDisc.this)) { - if (!TempBlock.isTempBlock(l.getBlock()) && (isEarthbendable(player, l.getBlock()) || isMetal(l.getBlock()) || meltable.contains(l.getBlock().getType().name()))) { - if (DensityShift.isPassiveSand(l.getBlock())) { - DensityShift.revertSand(l.getBlock()); - } - - if (lavaTrail) { - new RegenTempBlock(l.getBlock(), Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled) bd).setLevel(4)), regenTime); - - trailBlocks.add(l.getBlock()); - } else { - new RegenTempBlock(l.getBlock(), Material.AIR, Material.AIR.createBlockData(), regenTime); - } - - ParticleEffect.LAVA.display(l, particles * 2, Math.random(), Math.random(), Math.random(), 0.2); - } - } - } - } -} + private Location location; + private int recallCount; + + private long time; + + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.DURATION) + private long duration; + private int recallLimit; + private boolean trailFlow; + + private CompositeRemovalPolicy removalPolicy; + private DiscRenderer discRenderer; + private State state; + private final Set trailBlocks = new HashSet<>(); + + public LavaDisc(Player player) { + super(player); + + if (!bPlayer.canBend(this) || !bPlayer.canLavabend()) { + return; + } + + // Allow new LavaDisc if all existing instances for that player are in CleanupState. + for (LavaDisc disc : CoreAbility.getAbilities(player, LavaDisc.class)) { + if (!(disc.state instanceof CleanupState)) { + return; + } + } + + state = new HoldState(); + time = System.currentTimeMillis(); + discRenderer = new DiscRenderer(this.player); + + setFields(); + + if (prepare()) { + start(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + damage = config.getDouble("Abilities.Earth.LavaDisc.Damage"); + cooldown = config.getLong("Abilities.Earth.LavaDisc.Cooldown"); + duration = config.getLong("Abilities.Earth.LavaDisc.Duration"); + recallLimit = config.getInt("Abilities.Earth.LavaDisc.RecallLimit") - 1; + trailFlow = config.getBoolean("Abilities.Earth.LavaDisc.Destroy.TrailFlow"); + + this.removalPolicy = new CompositeRemovalPolicy(this, + new CannotBendRemovalPolicy(this.bPlayer, this, true, true), + new IsOfflineRemovalPolicy(this.player), + new IsDeadRemovalPolicy(this.player), + new SwappedSlotsRemovalPolicy<>(bPlayer, LavaDisc.class) + ); + + this.removalPolicy.load(config); + } + + private boolean prepare() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + long sourceRegen = config.getLong("Abilities.Earth.LavaDisc.Source.RegenTime"); + boolean lavaOnly = config.getBoolean("Abilities.Earth.LavaDisc.Source.LavaOnly"); + double sourceRange = config.getDouble("Abilities.Earth.LavaDisc.Source.Range"); + + Block lavaSource = getLavaSourceBlock(player, sourceRange); + if (lavaSource != null && !EarthAbility.getMovedEarth().containsKey(lavaSource)) { + new RegenTempBlock(lavaSource, Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(4)), sourceRegen); + return true; + } else { + Block earthSource = getEarthSourceBlock(sourceRange); + if (earthSource != null && !lavaOnly && !EarthAbility.getMovedEarth().containsKey(earthSource)) { + new RegenTempBlock(earthSource, Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(4)), sourceRegen); + return true; + } + } + + return false; + } + + @Override + public void progress() { + if (this.removalPolicy.shouldRemove()) { + if (!player.isOnline()) { + // Revert all of the lava blocks if the player goes offline. + for (Block block : trailBlocks) { + RegenTempBlock.revert(block); + } + bPlayer.addCooldown(this); + remove(); + return; + } else if (!(state instanceof CleanupState)) { + state = new CleanupState(); + } + } + + if (!hasAbility(player, LavaDisc.class)) { + return; + } + + state.update(); + } + + public static boolean canFlowFrom(Block from) { + Material type = from.getType(); + if (type != Material.LAVA && !ElementalAbility.isAir(type)) { + return true; + } + + for (LavaDisc disc : CoreAbility.getAbilities(LavaDisc.class)) { + if (disc.trailFlow) continue; + + if (disc.trailBlocks.contains(from)) { + return false; + } + } + + return true; + } + + private boolean isLocationSafe() { + if (!isLocationSafe(location)) { + return false; + } + + Block block = location.getBlock(); + + return isTransparent(block); + } + + private boolean isLocationSafe(Location location) { + if (location == null || location.getWorld() == null) { + return false; + } + + return location.getY() >= location.getWorld().getMinHeight() && location.getY() <= (location.getWorld().getMaxHeight() - 1); + } + + private void doDamage(Entity entity) { + DamageHandler.damageEntity(entity, damage, this); + entity.setFireTicks(20); + new FireDamageTimer(entity, player, this); + ParticleEffect.LAVA.display(entity.getLocation(), 15, Math.random(), Math.random(), Math.random(), 0.1); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getName() { + return "LavaDisc"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.LavaDisc.Description"); + } + + public void setLocation(Location location) { + this.location = location; + } + + public int getRecallCount() { + return recallCount; + } + + public void setRecallCount(int recallCount) { + this.recallCount = recallCount; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public int getRecallLimit() { + return recallLimit; + } + + public void setRecallLimit(int recallLimit) { + this.recallLimit = recallLimit; + } + + public boolean isTrailFlow() { + return trailFlow; + } + + public void setTrailFlow(boolean trailFlow) { + this.trailFlow = trailFlow; + } + + public DiscRenderer getDiscRenderer() { + return discRenderer; + } + + public void setDiscRenderer(DiscRenderer discRenderer) { + this.discRenderer = discRenderer; + } + + public State getState() { + return state; + } + + public void setState(State state) { + this.state = state; + } + + public Set getTrailBlocks() { + return trailBlocks; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.LavaDisc.Enabled"); + } + + private interface State { + void update(); + } + + // Renders the particles showing that the player is holding lava. + // Transitions to ForwardTravelState when the player stops sneaking. + private class HoldState implements State { + @Override + public void update() { + location = player.getEyeLocation(); + Vector dV = location.getDirection().normalize(); + location.add(new Vector(dV.getX() * 3, dV.getY() * 3, dV.getZ() * 3)); + + dV = dV.multiply(0.1); + + while (!isLocationSafe() && isLocationSafe(player.getLocation())) { + location.subtract(dV); + if (location.distanceSquared(player.getEyeLocation()) > (3 * 3)) { + break; + } + } + + discRenderer.render(location, false); + + location.setPitch(0); + + if (!player.isSneaking()) { + time = System.currentTimeMillis(); + state = new ForwardTravelState(location.getDirection().normalize()); + } + } + } + + private abstract class TravelState implements State { + private final boolean passHit; + + protected Vector direction; + protected boolean hasHit; + + public TravelState() { + this(player.getEyeLocation().getDirection()); + } + + public TravelState(Vector direction) { + this.direction = direction; + + ConfigurationSection config = JedCoreConfig.getConfig(player); + + passHit = config.getBoolean("Abilities.Earth.LavaDisc.ContinueAfterEntityHit"); + } + + protected void move() { + for (int i = 0; i < 5; i++) { + location = location.add(direction.clone().multiply(0.15)); + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2.0D)) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) { + doDamage(entity); + if (!passHit) { + hasHit = true; + return; + } + } + } + } + } + } + + // Moves the disc forward. Makes the disc destroy blocks if enabled. + // Transitions to ReverseTravelState if the player starts sneaking and can recall. + // Transitions to CleanupState if it times out or hits an entity. + private class ForwardTravelState extends TravelState { + public ForwardTravelState() { + this(player.getEyeLocation().getDirection()); + } + + public ForwardTravelState(Vector direction) { + super(direction); + } + + @Override + public void update() { + if (!isLocationSafe() || System.currentTimeMillis() > time + duration) { + state = new CleanupState(); + return; + } + + if (player.isSneaking() && recallCount <= recallLimit) { + state = new ReverseTravelState(); + return; + } + + alterPitch(); + move(); + discRenderer.render(location, true); + + if (hasHit) { + state = new CleanupState(); + } + } + + private void alterPitch() { + Location loc = player.getLocation().clone(); + + if (loc.getPitch() < -20) + loc.setPitch(-20); + if (loc.getPitch() > 20) + loc.setPitch(20); + + direction = loc.getDirection().normalize(); + } + } + + // Returns the disc to the player. + // Transitions to ForwardTravelState if the player stops sneaking. + // Transitions to HoldState if the disc gets close enough to the player. + private class ReverseTravelState extends TravelState { + @Override + public void update() { + if (!player.isSneaking()) { + state = new ForwardTravelState(); + return; + } + + Location loc = player.getEyeLocation(); + Vector dV = loc.getDirection().normalize(); + loc.add(new Vector(dV.getX() * 3, dV.getY() * 3, dV.getZ() * 3)); + + Vector vector = loc.toVector().subtract(location.toVector()); + direction = loc.setDirection(vector).getDirection().normalize(); + + move(); + discRenderer.render(location, true); + + double distanceAway = location.distance(loc); + if (distanceAway < 0.5) { + recallCount++; + // Player is holding the disc when it gets close enough to them. + state = new HoldState(); + } + } + } + + // Waits for the RegenTempBlocks to revert. + // This exists so the instance stays alive and block flow events can stop the lava from flowing. + private class CleanupState implements State { + private final long startTime; + private final long regenTime; + + public CleanupState() { + this.startTime = System.currentTimeMillis(); + + ConfigurationSection config = JedCoreConfig.getConfig(player); + + regenTime = config.getLong("Abilities.Earth.LavaDisc.Destroy.RegenTime"); + bPlayer.addCooldown(LavaDisc.this); + } + + @Override + public void update() { + if (System.currentTimeMillis() >= startTime + regenTime || trailBlocks.isEmpty()) { + remove(); + } + } + } + + private class DiscRenderer { + private final Player player; + private int angle; + + private final boolean damageBlocks; + private final List meltable; + private final long regenTime; + private final boolean lavaTrail; + + private final int particles; + + + public DiscRenderer(Player player) { + this.player = player; + this.angle = 0; + + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + damageBlocks = config.getBoolean("Abilities.Earth.LavaDisc.Destroy.BlockDamage"); + meltable = config.getStringList("Abilities.Earth.LavaDisc.Destroy.AdditionalMeltableBlocks"); + regenTime = config.getLong("Abilities.Earth.LavaDisc.Destroy.RegenTime"); + lavaTrail = config.getBoolean("Abilities.Earth.LavaDisc.Destroy.LavaTrail"); + particles = config.getInt("Abilities.Earth.LavaDisc.Particles"); + } + + void render(Location location, boolean largeLava) { + if (largeLava) + ParticleEffect.LAVA.display(location, particles * 2, Math.random(), Math.random(), Math.random(), 0.1); + else + ParticleEffect.LAVA.display(location, 1, Math.random(), Math.random(), Math.random(), 0.1); + + angle += 1; + if (angle > 360) + angle = 0; + + for (Location l : JCMethods.getCirclePoints(location, 20, 1, angle)) { + ParticleEffect.REDSTONE.display(l, 0, 196, 93, 0, 0.005F, new Particle.DustOptions(Color.fromRGB(196, 93, 0), 1)); + if (largeLava && damageBlocks) + damageBlocks(l); + } + + for (Location l : JCMethods.getCirclePoints(location, 10, 0.5, angle)) { + ParticleEffect.FLAME.display(l, 1, 0, 0, 0, 0.01); + ParticleEffect.SMOKE_NORMAL.display(l, 1, 0, 0, 0, 0.05); + if (largeLava && damageBlocks) + damageBlocks(l); + } + } + + private void damageBlocks(Location l) { + Block block = l.getBlock(); + if (EarthAbility.getMovedEarth().containsKey(block)) { + ParticleEffect.LAVA.display(l, 20, 0.5, 0.5, 0.5, 0.2); + ParticleEffect.BLOCK_CRACK.display(l, 15, 0.3, 0.3, 0.3, 0.15, Material.LAVA.createBlockData()); + return; + } + if (!RegionProtection.isRegionProtected(player, l, LavaDisc.this)) { + if (!TempBlock.isTempBlock(block) && (isEarthbendable(player, block) || isMetal(block) || meltable.contains(block.getType().name()))) { + if (DensityShift.isPassiveSand(block)) { + DensityShift.revertSand(block); + } + + if (lavaTrail) { + new RegenTempBlock(block, Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled) bd).setLevel(4)), regenTime); + + trailBlocks.add(block); + } else { + new RegenTempBlock(block, Material.AIR, Material.AIR.createBlockData(), regenTime); + } + + ParticleEffect.LAVA.display(l, particles * 2, Math.random(), Math.random(), Math.random(), 0.2); + } + } + } + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/LavaFlux.java b/src/com/jedk1/jedcore/ability/earthbending/LavaFlux.java index 6368fbf..4b836e2 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/LavaFlux.java +++ b/src/com/jedk1/jedcore/ability/earthbending/LavaFlux.java @@ -1,16 +1,17 @@ package com.jedk1.jedcore.ability.earthbending; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.EarthAbility; +import com.projectkorra.projectkorra.ability.LavaAbility; import com.projectkorra.projectkorra.attribute.Attribute; +import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.region.RegionProtection; +import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.Information; +import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; import org.bukkit.Location; import org.bukkit.Material; @@ -26,426 +27,419 @@ import org.bukkit.util.BlockIterator; import org.bukkit.util.Vector; -import com.jedk1.jedcore.JedCore; -import com.jedk1.jedcore.util.RegenTempBlock; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.LavaAbility; -import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; +import java.util.*; public class LavaFlux extends LavaAbility implements AddonAbility { - @Attribute(Attribute.SPEED) - private int speed; - @Attribute(Attribute.RANGE) - private int range; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.DURATION) - private long duration; - private long cleanup; - @Attribute(Attribute.DAMAGE) - private double damage; - private boolean wave; - - private Location location; - private int step; - private int counter; - private long time; - private boolean complete; - - private double knockUp; - private double knockBack; - - Random rand = new Random(); - - private static final BlockData LAVA = Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(1)); - - private final List flux = new ArrayList<>(); - - private Map blocks = new HashMap<>(); - private Map above = new HashMap<>(); - - public LavaFlux(Player player) { - super(player); - - if (!bPlayer.canBend(this) || !bPlayer.canLavabend()) { - return; - } - - setFields(); - time = System.currentTimeMillis(); - if (prepareLine()) { - start(); - if (!isRemoved()) { - bPlayer.addCooldown(this); - } - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - speed = config.getInt("Abilities.Earth.LavaFlux.Speed"); - if (speed < 1) speed = 1; - range = config.getInt("Abilities.Earth.LavaFlux.Range"); - cooldown = config.getLong("Abilities.Earth.LavaFlux.Cooldown"); - duration = config.getLong("Abilities.Earth.LavaFlux.Duration"); - cleanup = config.getLong("Abilities.Earth.LavaFlux.Cleanup"); - damage = config.getDouble("Abilities.Earth.LavaFlux.Damage"); - wave = config.getBoolean("Abilities.Earth.LavaFlux.Wave"); - knockUp = config.getDouble("Abilities.Earth.LavaFlux.KnockUp"); - knockBack = config.getDouble("Abilities.Earth.LavaFlux.KnockBack"); - } - - @Override - public void progress() { - if (player == null || !player.isOnline()) { - remove(); - return; - } - if (!bPlayer.canBendIgnoreCooldowns(this)) { - remove(); - return; - } - counter++; - if (!complete) { - if (speed <= 1 || counter % speed == 0) { - for (int i = 0; i <= 2; i++) { - step++; - progressFlux(); - } - } - } else if (duration > cleanup) { - if (System.currentTimeMillis() > time + duration) { - for (TempBlock tb : blocks.values()) { - if (!tb.isReverted()) tb.setType(Material.STONE); - } - remove(); - } - } - } - - private boolean prepareLine() { - Vector direction = player.getEyeLocation().getDirection().setY(0).normalize(); - Vector blockdirection = direction.clone().setX(Math.round(direction.getX())); - blockdirection = blockdirection.setZ(Math.round(direction.getZ())); - Location origin = player.getLocation().add(0, -1, 0).add(blockdirection.multiply(2)); - if (isEarthbendable(player, origin.getBlock())) { - BlockIterator bi = new BlockIterator(player.getWorld(), origin.toVector(), direction, 0, range); - - while (bi.hasNext()) { - Block b = bi.next(); - - if (b.getY() > b.getWorld().getMinHeight() && b.getY() < b.getWorld().getMaxHeight() && !RegionProtection.isRegionProtected(this, b.getLocation()) && !EarthAbility.getMovedEarth().containsKey(b)) { - if (isWater(b)) break; - while (!isEarthbendable(player, b)) { - b = b.getRelative(BlockFace.DOWN); - if (b.getY() < b.getWorld().getMinHeight() || b.getY() > b.getWorld().getMaxHeight()) { - break; - } - if (isEarthbendable(player, b)) { - break; - } - } - - while (!isTransparent(b.getRelative(BlockFace.UP))) { - b = b.getRelative(BlockFace.UP); - if (b.getY() < b.getWorld().getMinHeight() || b.getY() > b.getWorld().getMaxHeight()) { - break; - } - if (isEarthbendable(player, b.getRelative(BlockFace.UP))) { - break; - } - } - - if (isEarthbendable(player, b)) { - flux.add(b.getLocation()); - Block left = b.getRelative(getLeftBlockFace(GeneralMethods.getCardinalDirection(blockdirection)), 1); - expand(left); - Block right = b.getRelative(getLeftBlockFace(GeneralMethods.getCardinalDirection(blockdirection)).getOppositeFace(), 1); - expand(right); - } else { - break; - } - } - } - return true; - } - return false; - } - - private void progressFlux() { - for (Location location : flux) { - if (flux.indexOf(location) <= step) { - if (!blocks.containsKey(location.getBlock())) { //Make a new temp block if we haven't made one there before - blocks.put(location.getBlock(), new TempBlock(location.getBlock(), LAVA, duration + cleanup, this)); - } - - //new RegenTempBlock(location.getBlock(), Material.LAVA, LAVA, duration + cleanup); - this.location = location; - if (flux.indexOf(location) == step) { - Block above = location.getBlock().getRelative(BlockFace.UP); - ParticleEffect.LAVA.display(above.getLocation(), 2, Math.random(), Math.random(), Math.random(), 0); - applyDamageFromWave(above.getLocation()); - - if (isPlant(above) || isSnow(above)) { - final Block above2 = above.getRelative(BlockFace.UP); - if (isPlant(above) || isSnow(above)) { - TempBlock tb = new TempBlock(above, Material.AIR.createBlockData(), duration + cleanup, this); - this.above.put(above, tb); - if (isPlant(above2) && above2.getBlockData() instanceof Bisected) { - TempBlock tb2 = new TempBlock(above2, Material.AIR.createBlockData(), duration + cleanup + 30_000, this); - tb.addAttachedBlock(tb2); - } - } - } else if (wave && isTransparent(above)) { - new TempBlock(location.getBlock().getRelative(BlockFace.UP), LAVA, speed * 150L, this); - } - } - } - } - if (step >= flux.size()) { - wave = false; - complete = true; - time = System.currentTimeMillis(); - - for (TempBlock tb : blocks.values()) { //Make sure they all revert at the same time because it looks nice - long time = duration + cleanup + rand.nextInt(1000); - tb.setRevertTime(time); - - if (this.above.containsKey(tb.getBlock().getRelative(BlockFace.UP))) { - this.above.get(tb.getBlock().getRelative(BlockFace.UP)).setRevertTime(time); - } - } - } - } - - private void applyDamageFromWave(Location location) { - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 1.5)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) { - LivingEntity livingEntity = (LivingEntity) entity; - - DamageHandler.damageEntity(entity, damage, this); - new FireDamageTimer(entity, player, this); - - Vector direction = livingEntity.getLocation().toVector().subtract(player.getLocation().toVector()).normalize(); - Vector knockbackVelocity = direction.multiply(knockBack).setY(knockUp); - - livingEntity.setVelocity(knockbackVelocity); - } - } - } - - private void expand(Block block) { - if (block != null && block.getY() > block.getWorld().getMinHeight() && block.getY() < block.getWorld().getMaxHeight() && !RegionProtection.isRegionProtected(this, block.getLocation())) { - if (EarthAbility.getMovedEarth().containsKey(block)){ - Information info = EarthAbility.getMovedEarth().get(block); - if(!info.getBlock().equals(block)) { - return; - } - } - - if (isWater(block)) return; - while (!isEarthbendable(block)) { - block = block.getRelative(BlockFace.DOWN); - if (block.getY() < block.getWorld().getMinHeight() || block.getY() > block.getWorld().getMaxHeight()) { - break; - } - if (isEarthbendable(block)) { - break; - } - } - - while (!isTransparent(block.getRelative(BlockFace.UP))) { - block = block.getRelative(BlockFace.UP); - if (block.getY() < block.getWorld().getMinHeight() || block.getY() > block.getWorld().getMaxHeight()) { - break; - } - if (isEarthbendable(block.getRelative(BlockFace.UP))) { - break; - } - } - - if (isEarthbendable(block)) { - flux.add(block.getLocation()); - } - } - } - - public BlockFace getLeftBlockFace(BlockFace forward) { - switch (forward) { - case NORTH: - return BlockFace.WEST; - case SOUTH: - return BlockFace.EAST; - case WEST: - return BlockFace.SOUTH; - case NORTH_WEST: - return BlockFace.SOUTH_WEST; - case NORTH_EAST: - return BlockFace.NORTH_WEST; - case SOUTH_WEST: - return BlockFace.SOUTH_EAST; - case SOUTH_EAST: - return BlockFace.NORTH_EAST; - default: - return BlockFace.NORTH; - } - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public String getName() { - return "LavaFlux"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.LavaFlux.Description"); - } - - public int getSpeed() { - return speed; - } - - public void setSpeed(int speed) { - this.speed = speed; - } - - public int getRange() { - return range; - } - - public void setRange(int range) { - this.range = range; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - public long getCleanup() { - return cleanup; - } - - public void setCleanup(long cleanup) { - this.cleanup = cleanup; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public boolean isWave() { - return wave; - } - - public void setWave(boolean wave) { - this.wave = wave; - } - - public void setLocation(Location location) { - this.location = location; - } - - public int getStep() { - return step; - } - - public void setStep(int step) { - this.step = step; - } - - public int getCounter() { - return counter; - } - - public void setCounter(int counter) { - this.counter = counter; - } - - public long getTime() { - return time; - } - - public void setTime(long time) { - this.time = time; - } - - public boolean isComplete() { - return complete; - } - - public void setComplete(boolean complete) { - this.complete = complete; - } - - public List getFlux() { - return flux; - } - - @Override - public void load() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - if (config.get("Abilities.Earth.LavaFlux.Speed") instanceof String) { - config.set("Abilities.Earth.LavaFlux.Speed", 1); - JedCore.plugin.saveConfig(); - JedCore.plugin.reloadConfig(); - } - } - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.LavaFlux.Enabled"); - } + @Attribute(Attribute.SPEED) + private int speed; + @Attribute(Attribute.RANGE) + private int range; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.DURATION) + private long duration; + private long cleanup; + @Attribute(Attribute.DAMAGE) + private double damage; + private boolean wave; + + private Location location; + private int step; + private int counter; + private long time; + private boolean complete; + + private double knockUp; + private double knockBack; + + Random rand = new Random(); + + private static final BlockData LAVA = Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(1)); + + private final List flux = new ArrayList<>(); + + private Map blocks = new HashMap<>(); + private Map above = new HashMap<>(); + + public LavaFlux(Player player) { + super(player); + + if (!bPlayer.canBend(this) || !bPlayer.canLavabend()) { + return; + } + + setFields(); + time = System.currentTimeMillis(); + if (prepareLine()) { + start(); + if (!isRemoved()) { + bPlayer.addCooldown(this); + } + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + speed = config.getInt("Abilities.Earth.LavaFlux.Speed"); + if (speed < 1) speed = 1; + range = config.getInt("Abilities.Earth.LavaFlux.Range"); + cooldown = config.getLong("Abilities.Earth.LavaFlux.Cooldown"); + duration = config.getLong("Abilities.Earth.LavaFlux.Duration"); + cleanup = config.getLong("Abilities.Earth.LavaFlux.Cleanup"); + damage = config.getDouble("Abilities.Earth.LavaFlux.Damage"); + wave = config.getBoolean("Abilities.Earth.LavaFlux.Wave"); + knockUp = config.getDouble("Abilities.Earth.LavaFlux.KnockUp"); + knockBack = config.getDouble("Abilities.Earth.LavaFlux.KnockBack"); + } + + @Override + public void progress() { + if (player == null || !player.isOnline()) { + remove(); + return; + } + if (!bPlayer.canBendIgnoreCooldowns(this)) { + remove(); + return; + } + counter++; + if (!complete) { + if (speed <= 1 || counter % speed == 0) { + for (int i = 0; i <= 2; i++) { + step++; + progressFlux(); + } + } + } else if (duration > cleanup) { + if (System.currentTimeMillis() > time + duration) { + for (TempBlock tb : blocks.values()) { + if (!tb.isReverted()) tb.setType(Material.STONE); + } + remove(); + } + } + } + + private boolean prepareLine() { + Vector direction = player.getEyeLocation().getDirection().setY(0).normalize(); + Vector blockdirection = direction.clone().setX(Math.round(direction.getX())); + blockdirection = blockdirection.setZ(Math.round(direction.getZ())); + Location origin = player.getLocation().add(0, -1, 0).add(blockdirection.multiply(2)); + if (isEarthbendable(player, origin.getBlock())) { + BlockIterator bi = new BlockIterator(player.getWorld(), origin.toVector(), direction, 0, range); + + while (bi.hasNext()) { + Block b = bi.next(); + + if (b.getY() > b.getWorld().getMinHeight() && b.getY() < b.getWorld().getMaxHeight() && !RegionProtection.isRegionProtected(this, b.getLocation()) && !EarthAbility.getMovedEarth().containsKey(b)) { + if (isWater(b)) break; + while (!isEarthbendable(player, b)) { + b = b.getRelative(BlockFace.DOWN); + if (b.getY() < b.getWorld().getMinHeight() || b.getY() > b.getWorld().getMaxHeight()) { + break; + } + if (isEarthbendable(player, b)) { + break; + } + } + + while (!isTransparent(b.getRelative(BlockFace.UP))) { + b = b.getRelative(BlockFace.UP); + if (b.getY() < b.getWorld().getMinHeight() || b.getY() > b.getWorld().getMaxHeight()) { + break; + } + if (isEarthbendable(player, b.getRelative(BlockFace.UP))) { + break; + } + } + + if (isEarthbendable(player, b)) { + flux.add(b.getLocation()); + Block left = b.getRelative(getLeftBlockFace(GeneralMethods.getCardinalDirection(blockdirection)), 1); + expand(left); + Block right = b.getRelative(getLeftBlockFace(GeneralMethods.getCardinalDirection(blockdirection)).getOppositeFace(), 1); + expand(right); + } else { + break; + } + } + } + return true; + } + return false; + } + + private void progressFlux() { + for (Location location : flux) { + if (flux.indexOf(location) <= step) { + if (!blocks.containsKey(location.getBlock())) { //Make a new temp block if we haven't made one there before + blocks.put(location.getBlock(), new TempBlock(location.getBlock(), LAVA, duration + cleanup, this)); + } + + //new RegenTempBlock(location.getBlock(), Material.LAVA, LAVA, duration + cleanup); + this.location = location; + if (flux.indexOf(location) == step) { + Block above = location.getBlock().getRelative(BlockFace.UP); + ParticleEffect.LAVA.display(above.getLocation(), 2, Math.random(), Math.random(), Math.random(), 0); + applyDamageFromWave(above.getLocation()); + + if (isPlant(above) || isSnow(above)) { + final Block above2 = above.getRelative(BlockFace.UP); + if (isPlant(above) || isSnow(above)) { + TempBlock tb = new TempBlock(above, Material.AIR.createBlockData(), duration + cleanup, this); + this.above.put(above, tb); + if (isPlant(above2) && above2.getBlockData() instanceof Bisected) { + TempBlock tb2 = new TempBlock(above2, Material.AIR.createBlockData(), duration + cleanup + 30_000, this); + tb.addAttachedBlock(tb2); + } + } + } else if (wave && isTransparent(above)) { + new TempBlock(location.getBlock().getRelative(BlockFace.UP), LAVA, speed * 150L, this); + } + } + } + } + if (step >= flux.size()) { + wave = false; + complete = true; + time = System.currentTimeMillis(); + + for (TempBlock tb : blocks.values()) { //Make sure they all revert at the same time because it looks nice + long time = duration + cleanup + rand.nextInt(1000); + tb.setRevertTime(time); + + if (this.above.containsKey(tb.getBlock().getRelative(BlockFace.UP))) { + this.above.get(tb.getBlock().getRelative(BlockFace.UP)).setRevertTime(time); + } + } + } + } + + private void applyDamageFromWave(Location location) { + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 1.5)) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) { + LivingEntity livingEntity = (LivingEntity) entity; + + DamageHandler.damageEntity(entity, damage, this); + new FireDamageTimer(entity, player, this); + + Vector direction = livingEntity.getLocation().toVector().subtract(player.getLocation().toVector()).normalize(); + Vector knockbackVelocity = direction.multiply(knockBack).setY(knockUp); + + livingEntity.setVelocity(knockbackVelocity); + } + } + } + + private void expand(Block block) { + if (block != null && block.getY() > block.getWorld().getMinHeight() && block.getY() < block.getWorld().getMaxHeight() && !RegionProtection.isRegionProtected(this, block.getLocation())) { + if (EarthAbility.getMovedEarth().containsKey(block)){ + Information info = EarthAbility.getMovedEarth().get(block); + if(!info.getBlock().equals(block)) { + return; + } + } + + if (isWater(block)) return; + while (!isEarthbendable(block)) { + block = block.getRelative(BlockFace.DOWN); + if (block.getY() < block.getWorld().getMinHeight() || block.getY() > block.getWorld().getMaxHeight()) { + break; + } + if (isEarthbendable(block)) { + break; + } + } + + while (!isTransparent(block.getRelative(BlockFace.UP))) { + block = block.getRelative(BlockFace.UP); + if (block.getY() < block.getWorld().getMinHeight() || block.getY() > block.getWorld().getMaxHeight()) { + break; + } + if (isEarthbendable(block.getRelative(BlockFace.UP))) { + break; + } + } + + if (isEarthbendable(block)) { + flux.add(block.getLocation()); + } + } + } + + public BlockFace getLeftBlockFace(BlockFace forward) { + switch (forward) { + case NORTH: + return BlockFace.WEST; + case SOUTH: + return BlockFace.EAST; + case WEST: + return BlockFace.SOUTH; + case NORTH_WEST: + return BlockFace.SOUTH_WEST; + case NORTH_EAST: + return BlockFace.NORTH_WEST; + case SOUTH_WEST: + return BlockFace.SOUTH_EAST; + case SOUTH_EAST: + return BlockFace.NORTH_EAST; + default: + return BlockFace.NORTH; + } + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getName() { + return "LavaFlux"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.LavaFlux.Description"); + } + + public int getSpeed() { + return speed; + } + + public void setSpeed(int speed) { + this.speed = speed; + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public long getCleanup() { + return cleanup; + } + + public void setCleanup(long cleanup) { + this.cleanup = cleanup; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public boolean isWave() { + return wave; + } + + public void setWave(boolean wave) { + this.wave = wave; + } + + public void setLocation(Location location) { + this.location = location; + } + + public int getStep() { + return step; + } + + public void setStep(int step) { + this.step = step; + } + + public int getCounter() { + return counter; + } + + public void setCounter(int counter) { + this.counter = counter; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public boolean isComplete() { + return complete; + } + + public void setComplete(boolean complete) { + this.complete = complete; + } + + public List getFlux() { + return flux; + } + + @Override + public void load() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + if (config.get("Abilities.Earth.LavaFlux.Speed") instanceof String) { + config.set("Abilities.Earth.LavaFlux.Speed", 1); + JedCore.plugin.saveConfig(); + JedCore.plugin.reloadConfig(); + } + } + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.LavaFlux.Enabled"); + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/LavaThrow.java b/src/com/jedk1/jedcore/ability/earthbending/LavaThrow.java index 4fac307..2f3aab8 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/LavaThrow.java +++ b/src/com/jedk1/jedcore/ability/earthbending/LavaThrow.java @@ -5,15 +5,15 @@ import com.jedk1.jedcore.util.RegenTempBlock; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.LavaAbility; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - -import org.bukkit.Location; -import org.bukkit.Material; +import com.projectkorra.projectkorra.util.TempBlock; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.Levelled; @@ -21,328 +21,320 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; import java.util.concurrent.ConcurrentHashMap; public class LavaThrow extends LavaAbility implements AddonAbility { - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.RANGE) - private int range; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute(Attribute.SELECT_RANGE) - private int sourceRange; - private long sourceRegen; - @Attribute("MaxShots") - private int shotMax; - @Attribute(Attribute.FIRE_TICK) - private int fireTicks; - - private Location location; - private int shots; - - private final ConcurrentHashMap blasts = new ConcurrentHashMap<>(); - - public LavaThrow(Player player) { - super(player); - - if (hasAbility(player, LavaThrow.class)) { - LavaThrow.createBlast(player); - return; - } - - if (!bPlayer.canBend(this) || !bPlayer.canLavabend()) { - return; - } - - setFields(); - - location = player.getLocation(); - location.setPitch(0); - location = location.toVector().add(location.getDirection().multiply(sourceRange)).toLocation(location.getWorld()); - - sourceRange = Math.round(sourceRange / 2F); - - if (prepare()) { - start(); - if (!isRemoved()) { - createBlast(); - } - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Earth.LavaThrow.Cooldown"); - range = config.getInt("Abilities.Earth.LavaThrow.Range"); - damage = config.getDouble("Abilities.Earth.LavaThrow.Damage"); - sourceRange = config.getInt("Abilities.Earth.LavaThrow.SourceGrabRange"); - sourceRegen = config.getLong("Abilities.Earth.LavaThrow.SourceRegenDelay"); - shotMax = config.getInt("Abilities.Earth.LavaThrow.MaxShots"); - fireTicks = config.getInt("Abilities.Earth.LavaThrow.FireTicks"); - } - - @Override - public void progress() { - if (player == null || player.isDead() || !player.isOnline()) { - remove(); - return; - } - - if (player.getWorld() != location.getWorld()) { - bPlayer.addCooldown(this); - remove(); - return; - } - - if (!bPlayer.canBendIgnoreCooldowns(this)) { - bPlayer.addCooldown(this); - remove(); - return; - } - - if (shots >= shotMax) { - bPlayer.addCooldown(this); - } - - handleBlasts(); - - if (blasts.isEmpty()) { - bPlayer.addCooldown(this); - remove(); - } - } - - private boolean prepare() { - Block block = getRandomSourceBlock(location, 3); - - return block != null; - } - - public void createBlast() { - // TODO: This is just the worst. Fix it so it's not hidden distance selection. - Block source = getRandomSourceBlock(location, 3); - - if (source != null) { - shots++; - - Location origin = source.getLocation().clone().add(0, 2, 0); - double viewRange = range + origin.distance(player.getEyeLocation()); - Location viewTarget = GeneralMethods.getTargetedLocation(player, viewRange, Material.WATER, Material.LAVA); - Vector direction = viewTarget.clone().subtract(origin).toVector().normalize(); - Location head = origin.clone(); - - head.setDirection(direction); - blasts.put(head, origin); - - new RegenTempBlock(source.getRelative(BlockFace.UP), Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(0)), 200); - new RegenTempBlock(source, Material.AIR, Material.AIR.createBlockData(), sourceRegen, false); - } - } - - public void handleBlasts() { - for (Location l : blasts.keySet()) { - Location head = l.clone(); - Location origin = blasts.get(l); - - if (l.distance(origin) > range) { - blasts.remove(l); - continue; - } - - if(RegionProtection.isRegionProtected(this, l)){ - blasts.remove(l); - continue; - } - - if(GeneralMethods.isSolid(l.getBlock())){ - blasts.remove(l); - continue; - } - - head = head.add(head.getDirection().multiply(1)); - new RegenTempBlock(l.getBlock(), Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(0)), 200); - ParticleEffect.LAVA.display(head, 1, Math.random(), Math.random(), Math.random(), 0); - - boolean hit = false; - - for(Entity entity : GeneralMethods.getEntitiesAroundPoint(l, 2.0D)){ - if(entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !RegionProtection.isRegionProtected(this, entity.getLocation()) && !((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))){ - DamageHandler.damageEntity(entity, damage, this); - blasts.remove(l); - - hit = true; - entity.setFireTicks(this.fireTicks); - } - } - - if (!hit) { - blasts.remove(l); - blasts.put(head, origin); - } - } - } - - public static Block getRandomSourceBlock(Location location, int radius) { - Random rand = new Random(); - List checked = new ArrayList<>(); - List blocks = GeneralMethods.getBlocksAroundPoint(location, radius); - - for (int i = 0; i < blocks.size(); i++) { - int index = rand.nextInt(blocks.size()); - - while (checked.contains(index)) { - index = rand.nextInt(blocks.size()); - } - - checked.add(index); - - Block block = blocks.get(index); - - if (!LavaAbility.isLava(block)) { - continue; - } - - return block; - } - - return null; - } - - public static void createBlast(Player player) { - if (hasAbility(player, LavaThrow.class)) { - LavaThrow lt = getAbility(player, LavaThrow.class); - - if (lt.shots < lt.shotMax) { - lt.createBlast(); - } - } - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public String getName() { - return "LavaThrow"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.LavaThrow.Description"); - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public int getRange() { - return range; - } - - public void setRange(int range) { - this.range = range; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public int getSourceRange() { - return sourceRange; - } - - public void setSourceRange(int sourceRange) { - this.sourceRange = sourceRange; - } - - public long getSourceRegen() { - return sourceRegen; - } - - public void setSourceRegen(long sourceRegen) { - this.sourceRegen = sourceRegen; - } - - public int getShotMax() { - return shotMax; - } - - public void setShotMax(int shotMax) { - this.shotMax = shotMax; - } - - public int getFireTicks() { - return fireTicks; - } - - public void setFireTicks(int fireTicks) { - this.fireTicks = fireTicks; - } - - public void setLocation(Location location) { - this.location = location; - } - - public int getShots() { - return shots; - } - - public void setShots(int shots) { - this.shots = shots; - } - - public ConcurrentHashMap getBlasts() { - return blasts; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.LavaThrow.Enabled"); - } -} + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.RANGE) + private int range; + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute(Attribute.SELECT_RANGE) + private int sourceRange; + private long sourceRegen; + @Attribute("MaxShots") + private int shotMax; + @Attribute(Attribute.FIRE_TICK) + private int fireTicks; + @Attribute("CurveFactor") + private double curveFactor; + + private Location location; + private int shots; + private Block selectedSource; + private boolean isInitialState = true; + + private final ConcurrentHashMap blasts = new ConcurrentHashMap<>(); + + public LavaThrow(Player player) { + super(player); + + if (!bPlayer.canBend(this) || !bPlayer.canLavabend()) { + return; + } + + setFields(); + + location = player.getLocation(); + location.setPitch(0); + + if (prepare()) { + player.getWorld().playSound(selectedSource.getLocation(), Sound.ITEM_BUCKET_FILL_LAVA, 1.0f, 1.0f); + start(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Earth.LavaThrow.Cooldown"); + range = config.getInt("Abilities.Earth.LavaThrow.Range"); + damage = config.getDouble("Abilities.Earth.LavaThrow.Damage"); + sourceRange = config.getInt("Abilities.Earth.LavaThrow.SourceGrabRange"); + sourceRegen = config.getLong("Abilities.Earth.LavaThrow.SourceRegenDelay"); + shotMax = config.getInt("Abilities.Earth.LavaThrow.MaxShots"); + fireTicks = config.getInt("Abilities.Earth.LavaThrow.FireTicks"); + curveFactor = config.getDouble("Abilities.Earth.LavaThrow.CurveFactor"); + } + + @Override + public void progress() { + if (player == null || player.isDead() || !player.isOnline()) { + remove(); + return; + } + + if (!bPlayer.getBoundAbilityName().equalsIgnoreCase("LAVATHROW")) { + remove(); + if (shots > 0) bPlayer.addCooldown(this); + return; + } + + if (player.getLocation().distance(selectedSource.getLocation()) >= sourceRange) { + remove(); + if (shots > 0) bPlayer.addCooldown(this); + return; + } + + if (blasts.isEmpty() && shots >= shotMax && !isInitialState) { + remove(); + bPlayer.addCooldown(this); + return; + } + + selectedSource.getWorld().spawnParticle(Particle.FLAME, selectedSource.getLocation(), 2, 0.3, 1.0, 0.3, 0.05); + selectedSource.getWorld().spawnParticle(Particle.LAVA, selectedSource.getLocation(), 2, 0.2, 0.2, 0.2, 0); + + handleBlasts(); + } + + private boolean prepare() { + Block targetBlock = getTargetLavaBlock(sourceRange); + + if (targetBlock != null && !TempBlock.isTempBlock(targetBlock) && !EarthAbility.getMovedEarth().containsKey(targetBlock)) { + selectedSource = targetBlock; + return true; + } + + return false; + } + + public Block getTargetLavaBlock(int maxDistance) { + Location eyeLocation = player.getEyeLocation(); + Vector direction = eyeLocation.getDirection(); + World world = player.getWorld(); + + RayTraceResult result = world.rayTraceBlocks( + eyeLocation, direction, maxDistance, + FluidCollisionMode.ALWAYS, true + ); + + if (result != null) { + Block hitBlock = result.getHitBlock(); + if (LavaAbility.isLava(hitBlock)) { + return hitBlock; + } + } + return null; + } + + public void createBlast() { + if (selectedSource != null && shots < shotMax) { + isInitialState = false; + shots++; + + if (shots >= shotMax) { + bPlayer.addCooldown(this); + } + + Location origin = selectedSource.getLocation().clone().add(0, 2, 0); + player.getWorld().playSound(origin, Sound.ITEM_BUCKET_EMPTY_LAVA, 1.0f, 1.0f); + double viewRange = range + origin.distance(player.getEyeLocation()); + Location viewTarget = GeneralMethods.getTargetedLocation(player, viewRange, Material.WATER, Material.LAVA); + Vector direction = viewTarget.clone().subtract(origin).toVector().normalize(); + Location head = origin.clone(); + + head.setDirection(direction); + blasts.put(head, origin); + + new RegenTempBlock(selectedSource.getRelative(BlockFace.UP), Material.LAVA, + Material.LAVA.createBlockData(), 200); + } + } + + public void handleBlasts() { + for (Location l : blasts.keySet()) { + Location head = l.clone(); + Location origin = blasts.get(l); + + if (l.distance(origin) > range) { + blasts.remove(l); + continue; + } + + if (GeneralMethods.isSolid(l.getBlock())) { + blasts.remove(l); + continue; + } + + Vector currentDirection = head.getDirection(); + Vector playerLookDirection = player.getEyeLocation().getDirection(); + + Vector curveVector = playerLookDirection.clone() + .subtract(currentDirection) + .multiply(curveFactor); + + Vector newDirection = currentDirection.clone() + .add(curveVector) + .normalize(); + + head.setDirection(newDirection); + head = head.add(newDirection.multiply(1)); + + new RegenTempBlock(l.getBlock(), Material.LAVA, Material.LAVA.createBlockData(bd -> ((Levelled)bd).setLevel(0)), 200); + ParticleEffect.LAVA.display(head, 1, Math.random(), Math.random(), Math.random(), 0); + + boolean hit = false; + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(l, 2.0D)) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !RegionProtection.isRegionProtected(this, entity.getLocation()) && !((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))) { + DamageHandler.damageEntity(entity, damage, this); + blasts.remove(l); + + hit = true; + entity.setFireTicks(this.fireTicks); + } + } + + if (!hit) { + blasts.remove(l); + blasts.put(head, origin); + } + } + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getName() { + return "LavaThrow"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.LavaThrow.Description"); + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public int getSourceRange() { + return sourceRange; + } + + public void setSourceRange(int sourceRange) { + this.sourceRange = sourceRange; + } + + public long getSourceRegen() { + return sourceRegen; + } + + public void setSourceRegen(long sourceRegen) { + this.sourceRegen = sourceRegen; + } + + public int getShotMax() { + return shotMax; + } + + public void setShotMax(int shotMax) { + this.shotMax = shotMax; + } + + public int getFireTicks() { + return fireTicks; + } + + public void setFireTicks(int fireTicks) { + this.fireTicks = fireTicks; + } + + public void setLocation(Location location) { + this.location = location; + } + + public int getShots() { + return shots; + } + + public void setShots(int shots) { + this.shots = shots; + } + + public ConcurrentHashMap getBlasts() { + return blasts; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.LavaThrow.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/MagnetShield.java b/src/com/jedk1/jedcore/ability/earthbending/MagnetShield.java index 4373c5c..8eb0e43 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/MagnetShield.java +++ b/src/com/jedk1/jedcore/ability/earthbending/MagnetShield.java @@ -2,22 +2,15 @@ import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; - import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.MetalAbility; import com.projectkorra.projectkorra.attribute.Attribute; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Arrow; -import org.bukkit.entity.Entity; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Item; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; @@ -28,254 +21,254 @@ public class MagnetShield extends MetalAbility implements AddonAbility { - private static List METAL_LIST; - - private boolean isClickState = false; - private long startTime; - - @Attribute(Attribute.DURATION) - private long duration; - @Attribute(Attribute.RANGE) - private double range; - - private double velocity; - private boolean repelArrows; - private boolean repelLivingEntities; - private long shiftCooldown; - private long clickCooldown; - - public MagnetShield(Player player) { - super(player); - - if (!bPlayer.canBendIgnoreCooldowns(this) || !bPlayer.canMetalbend()) { - return; - } - - if (!bPlayer.canBend(this)) { - return; - } - - player.getWorld().playSound(player.getLocation(), Sound.BLOCK_CONDUIT_ACTIVATE, 1.0f, 1.5f); - - setFields(); - loadMaterialsFromConfig(); - start(); - } - - public MagnetShield(Player player, boolean isClickState) { - super(player); - - if (!bPlayer.canBendIgnoreCooldowns(this) || !bPlayer.canMetalbend()) { - return; - } - - if (!bPlayer.canBend(this)) { - return; - } - - if (hasAbility(player, MagnetShield.class)) { - getAbility(player, MagnetShield.class).remove(); - return; - } - - setFields(); - - if (isClickState) { - this.isClickState = true; - startTime = System.currentTimeMillis(); - bPlayer.addCooldown(this, duration + 1); - } - - player.getWorld().playSound(player.getLocation(), Sound.BLOCK_CONDUIT_ACTIVATE, 1.0f, 1.5f); - - loadMaterialsFromConfig(); - start(); - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - - if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { - remove(); - return; - } - - if (isClickState) { - if (System.currentTimeMillis() - startTime >= duration) { - bPlayer.addCooldown(this, clickCooldown); - remove(); - return; - } - } else { - if (!player.isSneaking()) { - bPlayer.addCooldown(this, shiftCooldown); - remove(); - return; - } - } - - renderMagneticFieldLines(); - repelMetal(); - } - - @Override - public long getCooldown() { - return 0; - } - - @Override - public Location getLocation() { - return player.getLocation(); - } - - @Override - public String getName() { - return "MagnetShield"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MagnetShield.Description"); - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.MagnetShield.Enabled"); - } - - private void renderMagneticFieldLines() { - Location playerLocation = player.getLocation(); - int numLoops = 5; - int pointsPerLoop = 30; - double verticalSpacing = 0.06; - - for (int loop = 0; loop < numLoops; loop++) { - double currentRadius = range * (1 - (double) loop / numLoops); - double currentHeight = ((loop - numLoops / 2.0) * verticalSpacing) + 0.3; - - for (int i = 0; i < pointsPerLoop; i++) { - double angle = 2 * Math.PI * i / pointsPerLoop; - double x = currentRadius * Math.cos(angle); - double z = currentRadius * Math.sin(angle); - Location particleLocation = playerLocation.clone().add(x, currentHeight, z); - JedCore.plugin.getParticleAdapter().displayMagneticParticles(particleLocation); - } - } - } - - private void loadMaterialsFromConfig() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - List materialNames = config.getStringList("Abilities.Earth.MagnetShield.Materials"); - METAL_LIST = new ArrayList<>(); - - for (String materialName : materialNames) { - Material material = Material.getMaterial(materialName.toUpperCase()); - if (material != null) { - METAL_LIST.add(material); - } else { - System.out.println("Invalid material in config: " + materialName); - } - } - } - - private void repelMetal() { - for (Entity e : GeneralMethods.getEntitiesAroundPoint(player.getLocation(), range)) { - if (e instanceof Item) { - Item i = (Item) e; - if (isMetalMaterial(i.getItemStack().getType())) { - Vector direction = GeneralMethods.getDirection(player.getLocation(), i.getLocation()).multiply(velocity); - i.setVelocity(direction); - } - } else if (e instanceof FallingBlock) { - FallingBlock fb = (FallingBlock) e; - - if (isMetalMaterial(fb.getBlockData().getMaterial())) { - Vector direction = GeneralMethods.getDirection(player.getLocation(), fb.getLocation()).multiply(velocity); - fb.setVelocity(direction); - fb.setDropItem(false); - } - } else if (e instanceof Arrow && repelArrows) { - Arrow arrow = (Arrow) e; - Vector currentVelocity = arrow.getVelocity(); - Vector reversedVelocity = currentVelocity.multiply(-1); - arrow.setVelocity(reversedVelocity); - } else if (e instanceof LivingEntity && repelLivingEntities) { - LivingEntity livingEntity = (LivingEntity) e; - - if (livingEntity.getUniqueId().equals(player.getUniqueId())) continue; - - EntityEquipment equipment = livingEntity.getEquipment(); - if (equipment == null) continue; - - ItemStack mainHand = equipment.getItemInMainHand(); - ItemStack offHand = equipment.getItemInOffHand(); - ItemStack helmet = equipment.getHelmet(); - ItemStack chestplate = equipment.getChestplate(); - ItemStack leggings = equipment.getLeggings(); - ItemStack boots = equipment.getBoots(); - - boolean isMetal = isMetalItem(mainHand) || isMetalItem(offHand) || - isMetalItem(helmet) || isMetalItem(chestplate) || - isMetalItem(leggings) || isMetalItem(boots); - - if (isMetal) { - Vector direction = GeneralMethods.getDirection(player.getLocation(), e.getLocation()).multiply(velocity); - livingEntity.setVelocity(direction); - } - } - } - } - - private boolean isMetalItem(ItemStack itemStack) { - return itemStack != null && METAL_LIST.contains(itemStack.getType()); - } - - private boolean isMetalMaterial(Material material) { - return METAL_LIST.contains(material); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - duration = config.getLong("Abilities.Earth.MagnetShield.Duration"); + private static List METAL_LIST; + + private boolean isClickState = false; + private long startTime; + + @Attribute(Attribute.DURATION) + private long duration; + @Attribute(Attribute.RANGE) + private double range; + + private double velocity; + private boolean repelArrows; + private boolean repelLivingEntities; + private long shiftCooldown; + private long clickCooldown; + + public MagnetShield(Player player) { + super(player); + + if (!bPlayer.canBendIgnoreCooldowns(this) || !bPlayer.canMetalbend()) { + return; + } + + if (!bPlayer.canBend(this)) { + return; + } + + player.getWorld().playSound(player.getLocation(), Sound.BLOCK_CONDUIT_ACTIVATE, 1.0f, 1.5f); + + setFields(); + loadMaterialsFromConfig(); + start(); + } + + public MagnetShield(Player player, boolean isClickState) { + super(player); + + if (!bPlayer.canBendIgnoreCooldowns(this) || !bPlayer.canMetalbend()) { + return; + } + + if (!bPlayer.canBend(this)) { + return; + } + + if (hasAbility(player, MagnetShield.class)) { + getAbility(player, MagnetShield.class).remove(); + return; + } + + setFields(); + + if (isClickState) { + this.isClickState = true; + startTime = System.currentTimeMillis(); + bPlayer.addCooldown(this, duration + 1); + } + + player.getWorld().playSound(player.getLocation(), Sound.BLOCK_CONDUIT_ACTIVATE, 1.0f, 1.5f); + + loadMaterialsFromConfig(); + start(); + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + + if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { + remove(); + return; + } + + if (isClickState) { + if (System.currentTimeMillis() - startTime >= duration) { + bPlayer.addCooldown(this, clickCooldown); + remove(); + return; + } + } else { + if (!player.isSneaking()) { + bPlayer.addCooldown(this, shiftCooldown); + remove(); + return; + } + } + + renderMagneticFieldLines(); + repelMetal(); + } + + @Override + public long getCooldown() { + return 0; + } + + @Override + public Location getLocation() { + return player.getLocation(); + } + + @Override + public String getName() { + return "MagnetShield"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MagnetShield.Description"); + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.MagnetShield.Enabled"); + } + + private void renderMagneticFieldLines() { + Location playerLocation = player.getLocation(); + int numLoops = 5; + int pointsPerLoop = 30; + double verticalSpacing = 0.06; + + for (int loop = 0; loop < numLoops; loop++) { + double currentRadius = range * (1 - (double) loop / numLoops); + double currentHeight = ((loop - numLoops / 2.0) * verticalSpacing) + 0.3; + + for (int i = 0; i < pointsPerLoop; i++) { + double angle = 2 * Math.PI * i / pointsPerLoop; + double x = currentRadius * Math.cos(angle); + double z = currentRadius * Math.sin(angle); + Location particleLocation = playerLocation.clone().add(x, currentHeight, z); + JedCore.plugin.getParticleAdapter().displayMagneticParticles(particleLocation); + } + } + } + + private void loadMaterialsFromConfig() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + List materialNames = config.getStringList("Abilities.Earth.MagnetShield.Materials"); + METAL_LIST = new ArrayList<>(); + + for (String materialName : materialNames) { + Material material = Material.getMaterial(materialName.toUpperCase()); + if (material != null) { + METAL_LIST.add(material); + } else { + System.out.println("Invalid material in config: " + materialName); + } + } + } + + private void repelMetal() { + for (Entity e : GeneralMethods.getEntitiesAroundPoint(player.getLocation(), range)) { + if (e instanceof Item) { + Item i = (Item) e; + if (isMetalMaterial(i.getItemStack().getType())) { + Vector direction = GeneralMethods.getDirection(player.getLocation(), i.getLocation()).multiply(velocity); + i.setVelocity(direction); + } + } else if (e instanceof FallingBlock) { + FallingBlock fb = (FallingBlock) e; + + if (isMetalMaterial(fb.getBlockData().getMaterial())) { + Vector direction = GeneralMethods.getDirection(player.getLocation(), fb.getLocation()).multiply(velocity); + fb.setVelocity(direction); + fb.setDropItem(false); + } + } else if (e instanceof Arrow && repelArrows) { + Arrow arrow = (Arrow) e; + Vector currentVelocity = arrow.getVelocity(); + Vector reversedVelocity = currentVelocity.multiply(-1); + arrow.setVelocity(reversedVelocity); + } else if (e instanceof LivingEntity && repelLivingEntities) { + LivingEntity livingEntity = (LivingEntity) e; + + if (livingEntity.getUniqueId().equals(player.getUniqueId())) continue; + + EntityEquipment equipment = livingEntity.getEquipment(); + if (equipment == null) continue; + + ItemStack mainHand = equipment.getItemInMainHand(); + ItemStack offHand = equipment.getItemInOffHand(); + ItemStack helmet = equipment.getHelmet(); + ItemStack chestplate = equipment.getChestplate(); + ItemStack leggings = equipment.getLeggings(); + ItemStack boots = equipment.getBoots(); + + boolean isMetal = isMetalItem(mainHand) || isMetalItem(offHand) || + isMetalItem(helmet) || isMetalItem(chestplate) || + isMetalItem(leggings) || isMetalItem(boots); + + if (isMetal) { + Vector direction = GeneralMethods.getDirection(player.getLocation(), e.getLocation()).multiply(velocity); + livingEntity.setVelocity(direction); + } + } + } + } + + private boolean isMetalItem(ItemStack itemStack) { + return itemStack != null && METAL_LIST.contains(itemStack.getType()); + } + + private boolean isMetalMaterial(Material material) { + return METAL_LIST.contains(material); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + duration = config.getLong("Abilities.Earth.MagnetShield.Duration"); shiftCooldown = config.getLong("Abilities.Earth.MagnetShield.Cooldowns.Shift"); - clickCooldown = config.getLong("Abilities.Earth.MagnetShield.Cooldowns.Click"); - range = config.getDouble("Abilities.Earth.MagnetShield.Range"); - repelArrows = config.getBoolean("Abilities.Earth.MagnetShield.RepelArrows"); - repelLivingEntities = config.getBoolean("Abilities.Earth.MagnetShield.RepelLivingEntities"); - velocity = config.getDouble("Abilities.Earth.MagnetShield.Velocity"); - } + clickCooldown = config.getLong("Abilities.Earth.MagnetShield.Cooldowns.Click"); + range = config.getDouble("Abilities.Earth.MagnetShield.Range"); + repelArrows = config.getBoolean("Abilities.Earth.MagnetShield.RepelArrows"); + repelLivingEntities = config.getBoolean("Abilities.Earth.MagnetShield.RepelLivingEntities"); + velocity = config.getDouble("Abilities.Earth.MagnetShield.Velocity"); + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/MetalArmor.java b/src/com/jedk1/jedcore/ability/earthbending/MetalArmor.java index ca1861e..8bca0c5 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/MetalArmor.java +++ b/src/com/jedk1/jedcore/ability/earthbending/MetalArmor.java @@ -8,7 +8,6 @@ import com.projectkorra.projectkorra.earthbending.EarthArmor; import com.projectkorra.projectkorra.util.TempArmor; import com.projectkorra.projectkorra.util.TempPotionEffect; - import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Material; @@ -23,190 +22,190 @@ public class MetalArmor extends EarthAbility implements AddonAbility { - private static final int GOLD_BLOCK_COLOR = 0xF2F204; - private static final List METAL_COLORS = Arrays.asList( - 0xa39d91, 0xf4f4f4, 0xa2a38f, 0xF2F204, 0xb75656, 0xfff4f4 - ); - - private boolean useIronArmor; - private int resistStrength; - private int resistDuration; - - public MetalArmor(Player player) { - super(player); - - if (bPlayer == null || !bPlayer.canBendIgnoreCooldowns(CoreAbility.getAbility(EarthArmor.class)) || !bPlayer.canMetalbend()) { - return; - } - - if (!CoreAbility.hasAbility(player, EarthArmor.class)) { - return; - } - - setFields(); - start(); - } - - private void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - useIronArmor = config.getBoolean("Abilities.Earth.EarthArmor.UseIronArmor"); - resistStrength = config.getInt("Abilities.Earth.EarthArmor.Resistance.Strength"); - resistDuration = config.getInt("Abilities.Earth.EarthArmor.Resistance.Duration"); - } - - @Override - public void progress() { - if (player == null || !player.isOnline() || player.isDead()) { - remove(); - return; - } - - if (!CoreAbility.hasAbility(player, EarthArmor.class)) { - remove(); - return; - } - - EarthArmor ea = CoreAbility.getAbility(player, EarthArmor.class); - if (!bPlayer.isToggled()) { - remove(); - ea.remove(); - return; - } - - if (ea.isFormed()) { - if (isMetalHelmet()) { - ItemStack[] armors = { new ItemStack(Material.CHAINMAIL_BOOTS, 1), - new ItemStack(Material.CHAINMAIL_LEGGINGS, 1), - new ItemStack(Material.CHAINMAIL_CHESTPLATE, 1), - new ItemStack(Material.CHAINMAIL_HELMET, 1) }; - - if(useIronArmor){ - armors = new ItemStack[]{ new ItemStack(Material.IRON_BOOTS, 1), - new ItemStack(Material.IRON_LEGGINGS, 1), - new ItemStack(Material.IRON_CHESTPLATE, 1), - new ItemStack(Material.IRON_HELMET, 1) }; - } - - if(useIronArmor && getHelmetColor().equals(Color.fromRGB(GOLD_BLOCK_COLOR))) { - armors = new ItemStack[]{ new ItemStack(Material.GOLDEN_BOOTS, 1), - new ItemStack(Material.GOLDEN_LEGGINGS, 1), - new ItemStack(Material.GOLDEN_CHESTPLATE, 1), - new ItemStack(Material.GOLDEN_HELMET, 1) }; - } - - player.getInventory().setArmorContents(armors); - - PotionEffect resistance = JedCore.plugin.getPotionEffectAdapter().getResistanceEffect(resistDuration, resistStrength); - new TempPotionEffect(player, resistance); - } - - remove(); - } - } - - private boolean isMetalHelmet() { - Color color = getHelmetColor(); - - return METAL_COLORS.contains(color.asRGB()); - } - - private Color getHelmetColor() { - if (!TempArmor.hasTempArmor(player)) { - return Color.BLACK; - } - - ItemStack helm = player.getInventory().getHelmet(); - if (helm.getType() != Material.LEATHER_HELMET) { - return Color.BLACK; - } - - LeatherArmorMeta meta = (LeatherArmorMeta)helm.getItemMeta(); - if (meta == null) { - return Color.BLACK; - } - - return meta.getColor(); - } - - @Override - public long getCooldown() { - return 0; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "MetalArmor"; - } - - @Override - public boolean isHiddenAbility() { - return true; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return false; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - return null; - } - - public boolean isUseIronArmor() { - return useIronArmor; - } - - public void setUseIronArmor(boolean useIronArmor) { - this.useIronArmor = useIronArmor; - } - - public int getResistStrength() { - return resistStrength; - } - - public void setResistStrength(int resistStrength) { - this.resistStrength = resistStrength; - } - - public int getResistDuration() { - return resistDuration; - } - - public void setResistDuration(int resistDuration) { - this.resistDuration = resistDuration; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.EarthArmor.Enabled"); - } -} + private static final int GOLD_BLOCK_COLOR = 0xF2F204; + private static final List METAL_COLORS = Arrays.asList( + 0xa39d91, 0xf4f4f4, 0xa2a38f, 0xF2F204, 0xb75656, 0xfff4f4 + ); + + private boolean useIronArmor; + private int resistStrength; + private int resistDuration; + + public MetalArmor(Player player) { + super(player); + + if (bPlayer == null || !bPlayer.canBendIgnoreCooldowns(CoreAbility.getAbility(EarthArmor.class)) || !bPlayer.canMetalbend()) { + return; + } + + if (!CoreAbility.hasAbility(player, EarthArmor.class)) { + return; + } + + setFields(); + start(); + } + + private void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + useIronArmor = config.getBoolean("Abilities.Earth.EarthArmor.UseIronArmor"); + resistStrength = config.getInt("Abilities.Earth.EarthArmor.Resistance.Strength"); + resistDuration = config.getInt("Abilities.Earth.EarthArmor.Resistance.Duration"); + } + + @Override + public void progress() { + if (player == null || !player.isOnline() || player.isDead()) { + remove(); + return; + } + + if (!CoreAbility.hasAbility(player, EarthArmor.class)) { + remove(); + return; + } + + EarthArmor ea = CoreAbility.getAbility(player, EarthArmor.class); + if (!bPlayer.isToggled()) { + remove(); + ea.remove(); + return; + } + + if (ea.isFormed()) { + if (isMetalHelmet()) { + ItemStack[] armors = { new ItemStack(Material.CHAINMAIL_BOOTS, 1), + new ItemStack(Material.CHAINMAIL_LEGGINGS, 1), + new ItemStack(Material.CHAINMAIL_CHESTPLATE, 1), + new ItemStack(Material.CHAINMAIL_HELMET, 1) }; + + if(useIronArmor){ + armors = new ItemStack[]{ new ItemStack(Material.IRON_BOOTS, 1), + new ItemStack(Material.IRON_LEGGINGS, 1), + new ItemStack(Material.IRON_CHESTPLATE, 1), + new ItemStack(Material.IRON_HELMET, 1) }; + } + + if(useIronArmor && getHelmetColor().equals(Color.fromRGB(GOLD_BLOCK_COLOR))) { + armors = new ItemStack[]{ new ItemStack(Material.GOLDEN_BOOTS, 1), + new ItemStack(Material.GOLDEN_LEGGINGS, 1), + new ItemStack(Material.GOLDEN_CHESTPLATE, 1), + new ItemStack(Material.GOLDEN_HELMET, 1) }; + } + + player.getInventory().setArmorContents(armors); + + PotionEffect resistance = JedCore.plugin.getPotionEffectAdapter().getResistanceEffect(resistDuration, resistStrength); + new TempPotionEffect(player, resistance); + } + + remove(); + } + } + + private boolean isMetalHelmet() { + Color color = getHelmetColor(); + + return METAL_COLORS.contains(color.asRGB()); + } + + private Color getHelmetColor() { + if (!TempArmor.hasTempArmor(player)) { + return Color.BLACK; + } + + ItemStack helm = player.getInventory().getHelmet(); + if (helm.getType() != Material.LEATHER_HELMET) { + return Color.BLACK; + } + + LeatherArmorMeta meta = (LeatherArmorMeta)helm.getItemMeta(); + if (meta == null) { + return Color.BLACK; + } + + return meta.getColor(); + } + + @Override + public long getCooldown() { + return 0; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "MetalArmor"; + } + + @Override + public boolean isHiddenAbility() { + return true; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return false; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + return null; + } + + public boolean isUseIronArmor() { + return useIronArmor; + } + + public void setUseIronArmor(boolean useIronArmor) { + this.useIronArmor = useIronArmor; + } + + public int getResistStrength() { + return resistStrength; + } + + public void setResistStrength(int resistStrength) { + this.resistStrength = resistStrength; + } + + public int getResistDuration() { + return resistDuration; + } + + public void setResistDuration(int resistDuration) { + this.resistDuration = resistDuration; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.EarthArmor.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/MetalFragments.java b/src/com/jedk1/jedcore/ability/earthbending/MetalFragments.java index 9a95cdd..134e1ee 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/MetalFragments.java +++ b/src/com/jedk1/jedcore/ability/earthbending/MetalFragments.java @@ -4,27 +4,18 @@ import com.jedk1.jedcore.configuration.JedCoreConfig; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.MetalAbility; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.region.RegionProtection; -import com.projectkorra.projectkorra.util.BlockSource; -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 com.projectkorra.projectkorra.util.TempFallingBlock; - +import com.projectkorra.projectkorra.util.*; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Entity; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Item; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; @@ -32,242 +23,247 @@ public class MetalFragments extends MetalAbility implements AddonAbility { - @Attribute("MaxSources") - private int maxSources; - @Attribute(Attribute.SELECT_RANGE) - private int selectRange; - @Attribute("MaxShots") - private int maxFragments; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - private double velocity; - - public List sources = new ArrayList<>(); - private final List thrownFragments = new ArrayList<>(); - private final List tblockTracker = new ArrayList<>(); - //private List fblockTracker = new ArrayList<>(); - private final HashMap counters = new HashMap<>(); - - public MetalFragments(Player player) { - super(player); - - if (hasAbility(player, MetalFragments.class)) { - MetalFragments.selectAnotherSource(player); - return; - } - - if (!bPlayer.canBend(this) || !bPlayer.canMetalbend()) { - return; - } - - setFields(); - - if (tblockTracker.size() >= maxSources) { - return; - } - - if (prepare()) { - Block b = selectSource(); - if (RegionProtection.isRegionProtected(player, b.getLocation(), this)) { - return; - } - - start(); - if (!isRemoved()) { - translateUpward(b); - } - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - maxSources = config.getInt("Abilities.Earth.MetalFragments.MaxSources"); - selectRange = config.getInt("Abilities.Earth.MetalFragments.SourceRange"); - maxFragments = config.getInt("Abilities.Earth.MetalFragments.MaxFragments"); - damage = config.getDouble("Abilities.Earth.MetalFragments.Damage"); - cooldown = config.getInt("Abilities.Earth.MetalFragments.Cooldown"); - velocity = config.getDouble("Abilities.Earth.MetalFragments.Velocity"); - } - - public static void shootFragment(Player player) { - if (hasAbility(player, MetalFragments.class)) { - getAbility(player, MetalFragments.class).shootFragment(); - } - } - - private void shootFragment() { - if (sources.size() <= 0) - return; - - Random randy = new Random(); - int i = randy.nextInt(sources.size()); - Block source = sources.get(i); - ItemStack is; - - switch (source.getType()) { - case GOLD_BLOCK: - case GOLD_ORE: - is = new ItemStack(Material.GOLD_INGOT, 1); - break; - case COAL_BLOCK: - is = new ItemStack(Material.COAL, 1); - break; - case COAL_ORE: - is = new ItemStack(Material.COAL_ORE, 1); - break; - default: - is = new ItemStack(Material.IRON_INGOT, 1); - break; - } - - Vector direction; - if (GeneralMethods.getTargetedEntity(player, 30, new ArrayList<>()) != null) { - direction = GeneralMethods.getDirection(source.getLocation(), GeneralMethods.getTargetedEntity(player, 30, new ArrayList<>()).getLocation()); - } else { - direction = GeneralMethods.getDirection(source.getLocation(), GeneralMethods.getTargetedLocation(player, 30)); - } - - Item ii = player.getWorld().dropItemNaturally(source.getLocation().getBlock().getRelative(GeneralMethods.getCardinalDirection(direction)).getLocation(), is); - ii.setPickupDelay(Integer.MAX_VALUE); - ii.setVelocity(direction.normalize().multiply(velocity)); - playMetalbendingSound(ii.getLocation()); - thrownFragments.add(ii); - - if (counters.containsKey(source)) { - int count = counters.get(source); - count++; - - if (count >= maxFragments) { - counters.remove(source); - source.getWorld().spawnFallingBlock(source.getLocation().add(0.5, 0, 0.5), source.getBlockData()); - TempBlock tempBlock = TempBlock.get(source); - if (tempBlock != null) { - tempBlock.revertBlock(); - } - sources.remove(source); - source.getWorld().playSound(source.getLocation(), Sound.ENTITY_ITEM_BREAK, 10, 5); - } else { - counters.put(source, count); - } - - if (sources.size() == 0) { - remove(); - } - } - } - - public static void selectAnotherSource(Player player) { - if (hasAbility(player, MetalFragments.class)) { - getAbility(player, MetalFragments.class).selectAnotherSource(); - } - } - - private void selectAnotherSource() { - if (tblockTracker.size() >= maxSources) - return; - - if (prepare()) { - Block b = selectSource(); - translateUpward(b); - } - } - - public boolean prepare() { - Block block = BlockSource.getEarthSourceBlock(player, selectRange, ClickType.SHIFT_DOWN); - - if (block == null) - return false; - - return isMetal(block); - } - - public Block selectSource() { - Block block = BlockSource.getEarthSourceBlock(player, selectRange, ClickType.SHIFT_DOWN); - if (isMetal(block)) - return block; - return null; - } - - public void translateUpward(Block block) { - if (block == null) - return; - - if (sources.contains(block)) - return; - - if (block.getRelative(BlockFace.UP).getType().isSolid()) - return; - - if (isEarthbendable(player, block)) { - new TempFallingBlock(block.getLocation().add(0.5, 0, 0.5), block.getBlockData(), new Vector(0, 0.8, 0), this); - block.setType(Material.AIR); - - playMetalbendingSound(block.getLocation()); - } - } - - public void progress() { - if (player == null || player.isDead() || !player.isOnline()) { - remove(); - return; - } - if (!hasAbility(player, MetalFragments.class)) { - return; - } - if (!bPlayer.canBendIgnoreCooldowns(this)) { - remove(); - return; - } - - Iterator itr = tblockTracker.iterator(); - while (itr.hasNext()) { - TempBlock tb = itr.next(); - if (player.getLocation().distance(tb.getLocation()) >= 10) { - player.getWorld().spawnFallingBlock(tb.getLocation().add(0.5,0.0,0.5), tb.getBlockData()); - sources.remove(tb.getBlock()); - tb.revertBlock(); - itr.remove(); - } - } - - for (TempFallingBlock tfb : TempFallingBlock.getFromAbility(this)) { - FallingBlock fb = tfb.getFallingBlock(); - if (fb.getLocation().getY() >= player.getEyeLocation().getY() + 1) { - Block block = fb.getLocation().getBlock(); - TempBlock tb = new TempBlock(block, fb.getBlockData()); - - tblockTracker.add(tb); - sources.add(tb.getBlock()); - counters.put(tb.getBlock(), 0); - tfb.remove(); - } - - if (fb.isOnGround()) { - fb.getLocation().getBlock().setBlockData(fb.getBlockData()); - } - } - for (ListIterator iterator = thrownFragments.listIterator(); iterator.hasNext();) { - Item f = iterator.next(); - - boolean touchedLiving = false; - for (Entity e : GeneralMethods.getEntitiesAroundPoint(f.getLocation(), 1)) { - if (e instanceof LivingEntity && e.getEntityId() != player.getEntityId()) { - touchedLiving = true; - DamageHandler.damageEntity(e, damage, this); - } - } - if (touchedLiving || f.isOnGround() || f.isDead()) { - ParticleEffect.ITEM_CRACK.display(f.getLocation(), 3, 0.3, 0.3, 0.3, 0.2, f.getItemStack()); - f.remove(); - iterator.remove(); - } - } - - //removeDeadFBlocks(); - } + @Attribute("MaxSources") + private int maxSources; + @Attribute(Attribute.SELECT_RANGE) + private int selectRange; + @Attribute("MaxShots") + private int maxFragments; + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + private double velocity; + + public List sources = new ArrayList<>(); + private final List thrownFragments = new ArrayList<>(); + private final List tblockTracker = new ArrayList<>(); + //private List fblockTracker = new ArrayList<>(); + private final HashMap counters = new HashMap<>(); + + public MetalFragments(Player player) { + super(player); + + if (hasAbility(player, MetalFragments.class)) { + MetalFragments.selectAnotherSource(player); + return; + } + + if (!bPlayer.canBend(this) || !bPlayer.canMetalbend()) { + return; + } + + setFields(); + + if (tblockTracker.size() >= maxSources) { + return; + } + + if (prepare()) { + Block b = selectSource(); + if (RegionProtection.isRegionProtected(player, b.getLocation(), this)) { + return; + } + + start(); + if (!isRemoved()) { + translateUpward(b); + } + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + maxSources = config.getInt("Abilities.Earth.MetalFragments.MaxSources"); + selectRange = config.getInt("Abilities.Earth.MetalFragments.SourceRange"); + maxFragments = config.getInt("Abilities.Earth.MetalFragments.MaxFragments"); + damage = config.getDouble("Abilities.Earth.MetalFragments.Damage"); + cooldown = config.getInt("Abilities.Earth.MetalFragments.Cooldown"); + velocity = config.getDouble("Abilities.Earth.MetalFragments.Velocity"); + } + + public static void shootFragment(Player player) { + if (hasAbility(player, MetalFragments.class)) { + getAbility(player, MetalFragments.class).shootFragment(); + } + } + + private void shootFragment() { + if (sources.size() <= 0) + return; + + Random randy = new Random(); + int i = randy.nextInt(sources.size()); + Block source = sources.get(i); + ItemStack is; + + switch (source.getType()) { + case GOLD_BLOCK: + case GOLD_ORE: + is = new ItemStack(Material.GOLD_INGOT, 1); + break; + case COAL_BLOCK: + is = new ItemStack(Material.COAL, 1); + break; + case COAL_ORE: + is = new ItemStack(Material.COAL_ORE, 1); + break; + default: + is = new ItemStack(Material.IRON_INGOT, 1); + break; + } + + Vector direction; + if (GeneralMethods.getTargetedEntity(player, 30, new ArrayList<>()) != null) { + direction = GeneralMethods.getDirection(source.getLocation(), GeneralMethods.getTargetedEntity(player, 30, new ArrayList<>()).getLocation()); + } else { + direction = GeneralMethods.getDirection(source.getLocation(), GeneralMethods.getTargetedLocation(player, 30)); + } + + Item ii = player.getWorld().dropItemNaturally(source.getLocation().getBlock().getRelative(GeneralMethods.getCardinalDirection(direction)).getLocation(), is); + ii.setPickupDelay(Integer.MAX_VALUE); + ii.setVelocity(direction.normalize().multiply(velocity)); + playMetalbendingSound(ii.getLocation()); + thrownFragments.add(ii); + + if (counters.containsKey(source)) { + int count = counters.get(source); + count++; + + if (count >= maxFragments) { + counters.remove(source); + source.getWorld().spawnFallingBlock(source.getLocation().add(0.5, 0, 0.5), source.getBlockData()); + TempBlock tempBlock = TempBlock.get(source); + if (tempBlock != null) { + tempBlock.revertBlock(); + } + sources.remove(source); + source.getWorld().playSound(source.getLocation(), Sound.ENTITY_ITEM_BREAK, 10, 5); + } else { + counters.put(source, count); + } + + if (sources.size() == 0) { + remove(); + } + } + } + + public static void selectAnotherSource(Player player) { + if (hasAbility(player, MetalFragments.class)) { + getAbility(player, MetalFragments.class).selectAnotherSource(); + } + } + + private void selectAnotherSource() { + if (tblockTracker.size() >= maxSources) + return; + + if (prepare()) { + Block b = selectSource(); + translateUpward(b); + } + } + + public boolean prepare() { + Block block = BlockSource.getEarthSourceBlock(player, selectRange, ClickType.SHIFT_DOWN); + + if (block == null) + return false; + + if (EarthAbility.getMovedEarth().containsKey(block)) + return false; + + return isMetal(block); + } + + public Block selectSource() { + Block block = BlockSource.getEarthSourceBlock(player, selectRange, ClickType.SHIFT_DOWN); + if (EarthAbility.getMovedEarth().containsKey(block)) + return null; + if (isMetal(block)) + return block; + return null; + } + + public void translateUpward(Block block) { + if (block == null) + return; + + if (sources.contains(block)) + return; + + if (block.getRelative(BlockFace.UP).getType().isSolid()) + return; + + if (isEarthbendable(player, block)) { + new TempFallingBlock(block.getLocation().add(0.5, 0, 0.5), block.getBlockData(), new Vector(0, 0.8, 0), this); + block.setType(Material.AIR); + + playMetalbendingSound(block.getLocation()); + } + } + + public void progress() { + if (player == null || player.isDead() || !player.isOnline()) { + remove(); + return; + } + if (!hasAbility(player, MetalFragments.class)) { + return; + } + if (!bPlayer.canBendIgnoreCooldowns(this)) { + remove(); + return; + } + + Iterator itr = tblockTracker.iterator(); + while (itr.hasNext()) { + TempBlock tb = itr.next(); + if (player.getLocation().distance(tb.getLocation()) >= 10) { + player.getWorld().spawnFallingBlock(tb.getLocation().add(0.5,0.0,0.5), tb.getBlockData()); + sources.remove(tb.getBlock()); + tb.revertBlock(); + itr.remove(); + } + } + + for (TempFallingBlock tfb : TempFallingBlock.getFromAbility(this)) { + FallingBlock fb = tfb.getFallingBlock(); + if (fb.getLocation().getY() >= player.getEyeLocation().getY() + 1) { + Block block = fb.getLocation().getBlock(); + TempBlock tb = new TempBlock(block, fb.getBlockData()); + + tblockTracker.add(tb); + sources.add(tb.getBlock()); + counters.put(tb.getBlock(), 0); + tfb.remove(); + } + + if (fb.isOnGround()) { + fb.getLocation().getBlock().setBlockData(fb.getBlockData()); + } + } + for (ListIterator iterator = thrownFragments.listIterator(); iterator.hasNext();) { + Item f = iterator.next(); + + boolean touchedLiving = false; + for (Entity e : GeneralMethods.getEntitiesAroundPoint(f.getLocation(), 1)) { + if (e instanceof LivingEntity && e.getEntityId() != player.getEntityId()) { + touchedLiving = true; + DamageHandler.damageEntity(e, damage, this); + } + } + if (touchedLiving || f.isOnGround() || f.isDead()) { + ParticleEffect.ITEM_CRACK.display(f.getLocation(), 3, 0.3, 0.3, 0.3, 0.2, f.getItemStack()); + f.remove(); + iterator.remove(); + } + } + + //removeDeadFBlocks(); + } /* public void removeDeadFBlocks() { @@ -277,154 +273,154 @@ public void removeDeadFBlocks() { } */ - public void removeDeadItems() { - thrownFragments.removeIf(Item::isDead); - } - - - public void dropSources() { - for (TempBlock tb : tblockTracker) { - tb.getBlock().getWorld().spawnFallingBlock(tb.getLocation().add(0.5,0.0,0.5), tb.getBlock().getBlockData()); - tb.revertBlock(); - } - - tblockTracker.clear(); - } - - public void removeFragments() { - for (Item i : thrownFragments) { - ParticleEffect.ITEM_CRACK.display(i.getLocation(), 3, 0.3, 0.3, 0.3, 0.2, i.getItemStack()); - i.remove(); - } - thrownFragments.clear(); - } - - public static void remove(Player player, Block block) { - if (hasAbility(player, MetalFragments.class)) { - MetalFragments mf = getAbility(player, MetalFragments.class); - if (mf.sources.contains(block)) { - mf.remove(); - } - } - } - - @Override - public void remove() { - dropSources(); - removeFragments(); - removeDeadItems(); - if (player.isOnline()) { - bPlayer.addCooldown(this); - } - super.remove(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "MetalFragments"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MetalFragments.Description"); - } - - public int getMaxSources() { - return maxSources; - } - - public void setMaxSources(int maxSources) { - this.maxSources = maxSources; - } - - public int getSelectRange() { - return selectRange; - } - - public void setSelectRange(int selectRange) { - this.selectRange = selectRange; - } - - public int getMaxFragments() { - return maxFragments; - } - - public void setMaxFragments(int maxFragments) { - this.maxFragments = maxFragments; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public List getSources() { - return sources; - } - - public void setSources(List sources) { - this.sources = sources; - } - - public List getThrownFragments() { - return thrownFragments; - } - - public List getTblockTracker() { - return tblockTracker; - } - - public HashMap getCounters() { - return counters; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.MetalFragments.Enabled"); - } -} + public void removeDeadItems() { + thrownFragments.removeIf(Item::isDead); + } + + + public void dropSources() { + for (TempBlock tb : tblockTracker) { + tb.getBlock().getWorld().spawnFallingBlock(tb.getLocation().add(0.5,0.0,0.5), tb.getBlock().getBlockData()); + tb.revertBlock(); + } + + tblockTracker.clear(); + } + + public void removeFragments() { + for (Item i : thrownFragments) { + ParticleEffect.ITEM_CRACK.display(i.getLocation(), 3, 0.3, 0.3, 0.3, 0.2, i.getItemStack()); + i.remove(); + } + thrownFragments.clear(); + } + + public static void remove(Player player, Block block) { + if (hasAbility(player, MetalFragments.class)) { + MetalFragments mf = getAbility(player, MetalFragments.class); + if (mf.sources.contains(block)) { + mf.remove(); + } + } + } + + @Override + public void remove() { + dropSources(); + removeFragments(); + removeDeadItems(); + if (player.isOnline()) { + bPlayer.addCooldown(this); + } + super.remove(); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "MetalFragments"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MetalFragments.Description"); + } + + public int getMaxSources() { + return maxSources; + } + + public void setMaxSources(int maxSources) { + this.maxSources = maxSources; + } + + public int getSelectRange() { + return selectRange; + } + + public void setSelectRange(int selectRange) { + this.selectRange = selectRange; + } + + public int getMaxFragments() { + return maxFragments; + } + + public void setMaxFragments(int maxFragments) { + this.maxFragments = maxFragments; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public List getSources() { + return sources; + } + + public void setSources(List sources) { + this.sources = sources; + } + + public List getThrownFragments() { + return thrownFragments; + } + + public List getTblockTracker() { + return tblockTracker; + } + + public HashMap getCounters() { + return counters; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.MetalFragments.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/MetalHook.java b/src/com/jedk1/jedcore/ability/earthbending/MetalHook.java index 3cbf551..218a17b 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/MetalHook.java +++ b/src/com/jedk1/jedcore/ability/earthbending/MetalHook.java @@ -6,7 +6,6 @@ import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.MetalAbility; - import com.projectkorra.projectkorra.attribute.Attribute; import org.bukkit.Location; import org.bukkit.Material; @@ -26,371 +25,371 @@ public class MetalHook extends MetalAbility implements AddonAbility { - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.RANGE) - private int range; - @Attribute("MaxHooks") - private int maxHooks; - private int totalHooks; - private int hooksUsed; - private boolean noSource; - private boolean barrierHooking; - - private boolean hasHook; - private boolean wasSprinting; - private long time; - - private Location destination; - - private final ConcurrentHashMap hooks = new ConcurrentHashMap<>(); - private final List hookIds = new ArrayList<>(); - - public MetalHook(Player player) { - super(player); - - if (!bPlayer.canBend(this) || !bPlayer.canMetalbend()) { - return; - } - - if (hasAbility(player, MetalHook.class)) { - MetalHook mh = getAbility(player, MetalHook.class); - mh.launchHook(); - return; - } - - setFields(); - - if (!hasRequiredInv()) { - return; - } - - wasSprinting = player.isSprinting(); - flightHandler.createInstance(player, this.getName()); - player.setAllowFlight(true); - - start(); - launchHook(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Earth.MetalHook.Cooldown"); - range = config.getInt("Abilities.Earth.MetalHook.Range"); - maxHooks = config.getInt("Abilities.Earth.MetalHook.MaxHooks"); - totalHooks = config.getInt("Abilities.Earth.MetalHook.TotalHooks"); - noSource = config.getBoolean("Abilities.Earth.MetalHook.RequireItem"); - barrierHooking = config.getBoolean("Abilities.Earth.MetalHook.BarrierHooking"); - } - - @Override - public void progress() { - if (player == null || !player.isOnline() || player.isDead()) { - removeAllArrows(); - remove(); - return; - } - - if (!bPlayer.canBendIgnoreBindsCooldowns(this) || hooks.isEmpty()) { - removeAllArrows(); - remove(); - return; - } - - if (!wasSprinting && player.isSprinting()) { - removeAllArrows(); - remove(); - return; - } - - wasSprinting = player.isSprinting(); - - if (player.isSneaking()) { - player.setVelocity(new Vector()); - - if (System.currentTimeMillis() > (time + 1000)) { - removeAllArrows(); - remove(); - return; - } - } else { - time = System.currentTimeMillis(); - } - - Vector target = new Vector(); - - for (Arrow a : hooks.keySet()) { - if (a != null) { - if (!isActiveArrow(a)) { - hooks.remove(a); - hookIds.remove(a.getUniqueId()); - a.remove(); - continue; - } - - if (a.getAttachedBlock() == null) { - hooks.replace(a, hooks.get(a), false); - } else { - hooks.replace(a, hooks.get(a), true); - hasHook = true; - } - - //Draws the particle lines. - for (Location location : JCMethods.getLinePoints(player.getLocation().add(0, 1, 0), a.getLocation(), ((int) player.getLocation().add(0,1,0).distance(a.getLocation()) * 2))) { - GeneralMethods.displayColoredParticle("#CCCCCC", location); - } - - if (hooks.get(a)) { - target.add(GeneralMethods.getDirection(player.getEyeLocation(), a.getLocation())); - } - } - } - - if (hasHook) { - destination = player.getLocation().clone().add(target); - - if (player.getLocation().distance(destination) > 2) { - player.setFlying(false); - double velocity = 0.8; - - GeneralMethods.setVelocity(this, player, target.clone().normalize().multiply(velocity)); - } else if (player.getLocation().distance(destination) < 2 && player.getLocation().distance(destination) >= 1) { - player.setFlying(false); - double velocity = 0.35; - - GeneralMethods.setVelocity(this, player, target.clone().normalize().multiply(velocity)); - } else { - GeneralMethods.setVelocity(this, player, new Vector(0, 0, 0)); - - if (player.getAllowFlight()) { - player.setFlying(true); - } - } - } - } - - private boolean isActiveArrow(Arrow arrow) { - if (arrow.isDead()) return false; - if (player.getWorld() != arrow.getWorld()) return false; - - Block attached = arrow.getAttachedBlock(); - - if (!barrierHooking && attached != null && attached.getType() == Material.BARRIER) return false; - - return player.getEyeLocation().distanceSquared(arrow.getLocation()) < range * range; - } - - @Override - public void remove() { - if (player.isOnline()) { - bPlayer.addCooldown(this); - } - - flightHandler.removeInstance(player, this.getName()); - - super.remove(); - } - - public void launchHook() { - if (!hasRequiredInv()) return; - - Vector dir = GeneralMethods.getDirection(player.getEyeLocation(), GeneralMethods.getTargetedLocation(player, range)); - - if (!hookIds.isEmpty() && hookIds.size() > (maxHooks - 1)) { - for (Arrow a : hooks.keySet()) { - if (a.getUniqueId().equals(hookIds.get(0))) { - hooks.remove(a); - hookIds.remove(0); - a.remove(); - break; - } - } - } - - if (totalHooks > 0 && hooksUsed++ > totalHooks) { - remove(); - return; - } - - Arrow a = player.getWorld().spawnArrow(player.getEyeLocation().add(player.getLocation().getDirection().multiply(2)), dir, 3, 0f); - a.setMetadata("metalhook", new FixedMetadataValue(JedCore.plugin, "1")); - - hooks.put(a, false); - hookIds.add(a.getUniqueId()); - } - - public void removeAllArrows() { - for (Arrow a : hooks.keySet()) { - a.remove(); - } - } - - public boolean hasRequiredInv() { - if (noSource) return true; - - if (player.getInventory().getChestplate() != null) { - Material[] chestplates = {Material.IRON_CHESTPLATE, Material.CHAINMAIL_CHESTPLATE}; - Material playerChest = player.getInventory().getChestplate().getType(); - - if (Arrays.asList(chestplates).contains(playerChest)) { - return true; - } - } - - Material[] metals = {Material.IRON_INGOT, Material.IRON_BLOCK}; - - for (ItemStack items : player.getInventory()) { - if (items != null && Arrays.asList(metals).contains(items.getType())) { - return true; - } - } - - return false; - } - - public int getMaxHooks() { - return this.maxHooks; - } - - public void setMaxHooks(int maxhooks) { - this.maxHooks = maxhooks; - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "MetalHook"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MetalHook.Description"); - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public int getRange() { - return range; - } - - public void setRange(int range) { - this.range = range; - } - - public int getTotalHooks() { - return totalHooks; - } - - public void setTotalHooks(int totalHooks) { - this.totalHooks = totalHooks; - } - - public int getHooksUsed() { - return hooksUsed; - } - - public void setHooksUsed(int hooksUsed) { - this.hooksUsed = hooksUsed; - } - - public boolean isNoSource() { - return noSource; - } - - public void setNoSource(boolean noSource) { - this.noSource = noSource; - } - - public boolean isBarrierHooking() { - return barrierHooking; - } - - public void setBarrierHooking(boolean barrierHooking) { - this.barrierHooking = barrierHooking; - } - - public boolean isHasHook() { - return hasHook; - } - - public void setHasHook(boolean hasHook) { - this.hasHook = hasHook; - } - - public boolean isWasSprinting() { - return wasSprinting; - } - - public void setWasSprinting(boolean wasSprinting) { - this.wasSprinting = wasSprinting; - } - - public long getTime() { - return time; - } - - public void setTime(long time) { - this.time = time; - } - - public Location getDestination() { - return destination; - } - - public void setDestination(Location destination) { - this.destination = destination; - } - - public ConcurrentHashMap getHooks() { - return hooks; - } - - public List getHookIds() { - return hookIds; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.MetalHook.Enabled"); - } -} + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.RANGE) + private int range; + @Attribute("MaxHooks") + private int maxHooks; + private int totalHooks; + private int hooksUsed; + private boolean noSource; + private boolean barrierHooking; + + private boolean hasHook; + private boolean wasSprinting; + private long time; + + private Location destination; + + private final ConcurrentHashMap hooks = new ConcurrentHashMap<>(); + private final List hookIds = new ArrayList<>(); + + public MetalHook(Player player) { + super(player); + + if (!bPlayer.canBend(this) || !bPlayer.canMetalbend()) { + return; + } + + if (hasAbility(player, MetalHook.class)) { + MetalHook mh = getAbility(player, MetalHook.class); + mh.launchHook(); + return; + } + + setFields(); + + if (!hasRequiredInv()) { + return; + } + + wasSprinting = player.isSprinting(); + flightHandler.createInstance(player, this.getName()); + player.setAllowFlight(true); + + start(); + launchHook(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Earth.MetalHook.Cooldown"); + range = config.getInt("Abilities.Earth.MetalHook.Range"); + maxHooks = config.getInt("Abilities.Earth.MetalHook.MaxHooks"); + totalHooks = config.getInt("Abilities.Earth.MetalHook.TotalHooks"); + noSource = config.getBoolean("Abilities.Earth.MetalHook.RequireItem"); + barrierHooking = config.getBoolean("Abilities.Earth.MetalHook.BarrierHooking"); + } + + @Override + public void progress() { + if (player == null || !player.isOnline() || player.isDead()) { + removeAllArrows(); + remove(); + return; + } + + if (!bPlayer.canBendIgnoreBindsCooldowns(this) || hooks.isEmpty()) { + removeAllArrows(); + remove(); + return; + } + + if (!wasSprinting && player.isSprinting()) { + removeAllArrows(); + remove(); + return; + } + + wasSprinting = player.isSprinting(); + + if (player.isSneaking()) { + player.setVelocity(new Vector()); + + if (System.currentTimeMillis() > (time + 1000)) { + removeAllArrows(); + remove(); + return; + } + } else { + time = System.currentTimeMillis(); + } + + Vector target = new Vector(); + + for (Arrow a : hooks.keySet()) { + if (a != null) { + if (!isActiveArrow(a)) { + hooks.remove(a); + hookIds.remove(a.getUniqueId()); + a.remove(); + continue; + } + + if (a.getAttachedBlock() == null) { + hooks.replace(a, hooks.get(a), false); + } else { + hooks.replace(a, hooks.get(a), true); + hasHook = true; + } + + //Draws the particle lines. + for (Location location : JCMethods.getLinePoints(player.getLocation().add(0, 1, 0), a.getLocation(), ((int) player.getLocation().add(0,1,0).distance(a.getLocation()) * 2))) { + GeneralMethods.displayColoredParticle("#CCCCCC", location); + } + + if (hooks.get(a)) { + target.add(GeneralMethods.getDirection(player.getEyeLocation(), a.getLocation())); + } + } + } + + if (hasHook) { + destination = player.getLocation().clone().add(target); + + if (player.getLocation().distance(destination) > 2) { + player.setFlying(false); + double velocity = 0.8; + + GeneralMethods.setVelocity(this, player, target.clone().normalize().multiply(velocity)); + } else if (player.getLocation().distance(destination) < 2 && player.getLocation().distance(destination) >= 1) { + player.setFlying(false); + double velocity = 0.35; + + GeneralMethods.setVelocity(this, player, target.clone().normalize().multiply(velocity)); + } else { + GeneralMethods.setVelocity(this, player, new Vector(0, 0, 0)); + + if (player.getAllowFlight()) { + player.setFlying(true); + } + } + } + } + + private boolean isActiveArrow(Arrow arrow) { + if (arrow.isDead()) return false; + if (player.getWorld() != arrow.getWorld()) return false; + + Block attached = arrow.getAttachedBlock(); + + if (!barrierHooking && attached != null && attached.getType() == Material.BARRIER) return false; + + return player.getEyeLocation().distanceSquared(arrow.getLocation()) < range * range; + } + + @Override + public void remove() { + if (player.isOnline()) { + bPlayer.addCooldown(this); + } + + flightHandler.removeInstance(player, this.getName()); + + super.remove(); + } + + public void launchHook() { + if (!hasRequiredInv()) return; + + Vector dir = GeneralMethods.getDirection(player.getEyeLocation(), GeneralMethods.getTargetedLocation(player, range)); + + if (!hookIds.isEmpty() && hookIds.size() > (maxHooks - 1)) { + for (Arrow a : hooks.keySet()) { + if (a.getUniqueId().equals(hookIds.get(0))) { + hooks.remove(a); + hookIds.remove(0); + a.remove(); + break; + } + } + } + + if (totalHooks > 0 && hooksUsed++ > totalHooks) { + remove(); + return; + } + + Arrow a = player.getWorld().spawnArrow(player.getEyeLocation().add(player.getLocation().getDirection().multiply(2)), dir, 3, 0f); + a.setMetadata("metalhook", new FixedMetadataValue(JedCore.plugin, "1")); + + hooks.put(a, false); + hookIds.add(a.getUniqueId()); + } + + public void removeAllArrows() { + for (Arrow a : hooks.keySet()) { + a.remove(); + } + } + + public boolean hasRequiredInv() { + if (noSource) return true; + + if (player.getInventory().getChestplate() != null) { + Material[] chestplates = {Material.IRON_CHESTPLATE, Material.CHAINMAIL_CHESTPLATE}; + Material playerChest = player.getInventory().getChestplate().getType(); + + if (Arrays.asList(chestplates).contains(playerChest)) { + return true; + } + } + + Material[] metals = {Material.IRON_INGOT, Material.IRON_BLOCK}; + + for (ItemStack items : player.getInventory()) { + if (items != null && Arrays.asList(metals).contains(items.getType())) { + return true; + } + } + + return false; + } + + public int getMaxHooks() { + return this.maxHooks; + } + + public void setMaxHooks(int maxhooks) { + this.maxHooks = maxhooks; + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "MetalHook"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MetalHook.Description"); + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public int getTotalHooks() { + return totalHooks; + } + + public void setTotalHooks(int totalHooks) { + this.totalHooks = totalHooks; + } + + public int getHooksUsed() { + return hooksUsed; + } + + public void setHooksUsed(int hooksUsed) { + this.hooksUsed = hooksUsed; + } + + public boolean isNoSource() { + return noSource; + } + + public void setNoSource(boolean noSource) { + this.noSource = noSource; + } + + public boolean isBarrierHooking() { + return barrierHooking; + } + + public void setBarrierHooking(boolean barrierHooking) { + this.barrierHooking = barrierHooking; + } + + public boolean isHasHook() { + return hasHook; + } + + public void setHasHook(boolean hasHook) { + this.hasHook = hasHook; + } + + public boolean isWasSprinting() { + return wasSprinting; + } + + public void setWasSprinting(boolean wasSprinting) { + this.wasSprinting = wasSprinting; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public Location getDestination() { + return destination; + } + + public void setDestination(Location destination) { + this.destination = destination; + } + + public ConcurrentHashMap getHooks() { + return hooks; + } + + public List getHookIds() { + return hookIds; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.MetalHook.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/MetalShred.java b/src/com/jedk1/jedcore/ability/earthbending/MetalShred.java index ef79f8c..dac3122 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/MetalShred.java +++ b/src/com/jedk1/jedcore/ability/earthbending/MetalShred.java @@ -4,6 +4,7 @@ import com.jedk1.jedcore.configuration.JedCoreConfig; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.ElementalAbility; import com.projectkorra.projectkorra.ability.MetalAbility; import com.projectkorra.projectkorra.attribute.Attribute; @@ -13,7 +14,6 @@ import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.TempBlock; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -29,455 +29,458 @@ public class MetalShred extends MetalAbility implements AddonAbility { - @Attribute(Attribute.SELECT_RANGE) - private int selectRange; - private int extendTick; - @Attribute(Attribute.DAMAGE) - private double damage; - - private boolean horizontal = false; - private boolean started = false; - private boolean stop = false; - private boolean stopCoil = false; - private boolean extending = false; - private int length = 0; - private int fullLength = 0; - private long lastExtendTime; - private Block source; - private Block lastBlock; - private final List tblocks = new ArrayList<>(); - - public MetalShred(Player player) { - super(player); - - if (hasAbility(player, MetalShred.class)) { - getAbility(player, MetalShred.class).remove(); - } - - if (!bPlayer.canBend(this)) { - return; - } - - setFields(); - - if (selectSource()) { - if (horizontal) { - raiseBlock(source, GeneralMethods.getDirection(player.getLocation(), source.getLocation())); - } else { - shiftBlock(source, GeneralMethods.getDirection(player.getLocation(), source.getLocation())); - } - - start(); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - selectRange = config.getInt("Abilities.Earth.MetalShred.SourceRange"); - extendTick = config.getInt("Abilities.Earth.MetalShred.ExtendTick"); - damage = config.getDouble("Abilities.Earth.MetalShred.Damage"); - } - - public boolean selectSource() { - Block b = BlockSource.getEarthSourceBlock(player, selectRange, ClickType.SHIFT_DOWN); - - if (!isMetal(b)) - return false; - - source = b; - - if (ElementalAbility.isAir(source.getRelative(BlockFace.UP).getType()) && !isMetal(source.getRelative(BlockFace.DOWN))) { - horizontal = true; - } - - return true; - } - - public void raiseBlock(Block b, Vector d) { - Block up = b.getRelative(BlockFace.UP); - Block away = b.getRelative(GeneralMethods.getCardinalDirection(d)); - Block awayup = away.getRelative(BlockFace.UP); - Block deeperb = b.getRelative(BlockFace.DOWN); - Block deepera = away.getRelative(BlockFace.DOWN); - - for (TempBlock tb : tblocks) { - if (!ElementalAbility.isAir(tb.getBlock().getType())) - tb.setType(Material.AIR); - } - - if (!up.getType().isSolid()) { - TempBlock tbu = new TempBlock(up, b.getBlockData()); - tblocks.add(tbu); - } - - if (!awayup.getType().isSolid()) { - TempBlock tbau = new TempBlock(awayup, away.getBlockData()); - tblocks.add(tbau); - } - - if (isMetal(b)) { - TempBlock tbd = new TempBlock(b, Material.AIR.createBlockData()); - tblocks.add(tbd); - } - - if (isMetal(away)) { - TempBlock tba = new TempBlock(away, Material.AIR.createBlockData()); - tblocks.add(tba); - } - - if (isMetal(deeperb)) { - TempBlock tbdb = new TempBlock(deeperb, Material.AIR.createBlockData()); - tblocks.add(tbdb); - } - - if (isMetal(deepera)) { - TempBlock tbda = new TempBlock(deepera, Material.AIR.createBlockData()); - tblocks.add(tbda); - } - - playMetalbendingSound(b.getLocation()); - } - - public void shiftBlock(Block b, Vector d) { - Block under = b.getRelative(BlockFace.DOWN); - Block side = b.getRelative(GeneralMethods.getCardinalDirection(d).getOppositeFace()); - Block underside = under.getRelative(GeneralMethods.getCardinalDirection(d).getOppositeFace()); - - for (TempBlock tb : tblocks) { - if (!ElementalAbility.isAir(tb.getBlock().getType())) - tb.setType(Material.AIR); - } - - if (!side.getType().isSolid()) { - TempBlock tbs = new TempBlock(side, b.getBlockData()); - tblocks.add(tbs); - } - - if (!underside.getType().isSolid()) { - TempBlock tbus = new TempBlock(underside, under.getBlockData()); - tblocks.add(tbus); - } - - if (isMetal(b)) { - TempBlock tb1 = new TempBlock(b, Material.AIR.createBlockData()); - tblocks.add(tb1); - } - - if (isMetal(under)) { - TempBlock tb2 = new TempBlock(under, Material.AIR.createBlockData()); - tblocks.add(tb2); - } - - playMetalbendingSound(b.getLocation()); - } - - private void peelCoil(Block b) { - Block under = b.getRelative(BlockFace.DOWN); - - if (length <= 0) - return; - - if (!b.getType().isSolid()) { - TempBlock tbb = new TempBlock(b, Material.IRON_BLOCK.createBlockData()); - tblocks.add(tbb); - } - - else - stopCoil = true; - - if (!under.getType().isSolid()) { - TempBlock tbu = new TempBlock(under, Material.IRON_BLOCK.createBlockData()); - tblocks.add(tbu); - } - - else - stopCoil = true; - - playMetalbendingSound(b.getLocation()); - - length--; - } - - public static void startShred(Player player) { - if (hasAbility(player, MetalShred.class)) { - getAbility(player, MetalShred.class).startShred(); - } - } - - private void startShred() { - started = true; - } - - public static void extend(Player player) { - if (hasAbility(player, MetalShred.class)) { - getAbility(player, MetalShred.class).extend(); - } - } - - private void extend() { - if (extending) { - extending = false; - return; - } - - if (!stop) - return; - - lastExtendTime = System.currentTimeMillis(); - fullLength = length; - if (lastBlock != null) - lastBlock = lastBlock.getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(player.getLocation(), lastBlock.getLocation())).getOppositeFace()); - else { - return; - } - extending = true; - } - - @Override - public void progress() { - if (!player.isOnline() || player.isDead()) { - remove(); - return; - } - - if (!bPlayer.canBendIgnoreCooldowns(this)) { - remove(); - return; - } - - if (!player.isSprinting()) { - if (started) - stop = true; - } - - if (!horizontal && stop && !stopCoil && extending && System.currentTimeMillis() > lastExtendTime + extendTick) { - lastExtendTime = System.currentTimeMillis(); - if (length > 0) { - - Block b = lastBlock.getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(lastBlock.getLocation(), GeneralMethods.getTargetedLocation(player, fullLength)))); - - peelCoil(b); - - for (Entity e : GeneralMethods.getEntitiesAroundPoint(b.getLocation(), 2)) { - if (!(e instanceof LivingEntity) || e.getEntityId() == player.getEntityId()) { - continue; - } - if (RegionProtection.isRegionProtected(this, e.getLocation()) || ((e instanceof Player) && Commands.invincible.contains(e.getName()))) { - continue; - } - DamageHandler.damageEntity(e, damage, this); - GeneralMethods.setVelocity(this, e, e.getVelocity().add(player.getLocation().getDirection().add(new Vector(0, 0.1, 0)))); - } - - lastBlock = b; - } - - return; - } - - if (stop || !started) - return; - - Block b; - - if (lastBlock != null) { - b = lastBlock.getRelative(GeneralMethods.getCardinalDirection(player.getLocation().getDirection())); - } - - else { - b = source.getRelative(GeneralMethods.getCardinalDirection(player.getLocation().getDirection())); - } - - if (!isMetal(b)) { - if (!ElementalAbility.isAir(b.getType())) { - remove(); - } - return; - } - - if (b.getLocation().getX() == player.getLocation().getBlockX() || b.getLocation().getZ() == player.getLocation().getBlockZ()) { - if (horizontal) - raiseBlock(b, GeneralMethods.getDirection(player.getLocation(), b.getLocation())); - else - shiftBlock(b, GeneralMethods.getDirection(player.getLocation(), b.getLocation())); - - length++; - lastBlock = b; - } - } - - private void revertAll() { - for (TempBlock tb : tblocks) { - tb.revertBlock(); - } - } - - @Override - public void remove() { - revertAll(); - super.remove(); - } - - @Override - public long getCooldown() { - return 0; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "MetalShred"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MetalShred.Description"); - } - - public int getSelectRange() { - return selectRange; - } - - public void setSelectRange(int selectRange) { - this.selectRange = selectRange; - } - - public int getExtendTick() { - return extendTick; - } - - public void setExtendTick(int extendTick) { - this.extendTick = extendTick; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public boolean isHorizontal() { - return horizontal; - } - - public void setHorizontal(boolean horizontal) { - this.horizontal = horizontal; - } - - @Override - public boolean isStarted() { - return started; - } - - public void setStarted(boolean started) { - this.started = started; - } - - public boolean isStop() { - return stop; - } - - public void setStop(boolean stop) { - this.stop = stop; - } - - public boolean isStopCoil() { - return stopCoil; - } - - public void setStopCoil(boolean stopCoil) { - this.stopCoil = stopCoil; - } - - public boolean isExtending() { - return extending; - } - - public void setExtending(boolean extending) { - this.extending = extending; - } - - public int getLength() { - return length; - } - - public void setLength(int length) { - this.length = length; - } - - public int getFullLength() { - return fullLength; - } - - public void setFullLength(int fullLength) { - this.fullLength = fullLength; - } - - public long getLastExtendTime() { - return lastExtendTime; - } - - public void setLastExtendTime(long lastExtendTime) { - this.lastExtendTime = lastExtendTime; - } - - public Block getSource() { - return source; - } - - public void setSource(Block source) { - this.source = source; - } - - public Block getLastBlock() { - return lastBlock; - } - - public void setLastBlock(Block lastBlock) { - this.lastBlock = lastBlock; - } - - public List getTblocks() { - return tblocks; - } - - @Override - public void load() {} + @Attribute(Attribute.SELECT_RANGE) + private int selectRange; + private int extendTick; + @Attribute(Attribute.DAMAGE) + private double damage; + + private boolean horizontal = false; + private boolean started = false; + private boolean stop = false; + private boolean stopCoil = false; + private boolean extending = false; + private int length = 0; + private int fullLength = 0; + private long lastExtendTime; + private Block source; + private Block lastBlock; + private final List tblocks = new ArrayList<>(); + + public MetalShred(Player player) { + super(player); + + if (hasAbility(player, MetalShred.class)) { + getAbility(player, MetalShred.class).remove(); + } + + if (!bPlayer.canBend(this)) { + return; + } + + setFields(); + + if (selectSource()) { + if (horizontal) { + raiseBlock(source, GeneralMethods.getDirection(player.getLocation(), source.getLocation())); + } else { + shiftBlock(source, GeneralMethods.getDirection(player.getLocation(), source.getLocation())); + } + + start(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + selectRange = config.getInt("Abilities.Earth.MetalShred.SourceRange"); + extendTick = config.getInt("Abilities.Earth.MetalShred.ExtendTick"); + damage = config.getDouble("Abilities.Earth.MetalShred.Damage"); + } + + public boolean selectSource() { + Block b = BlockSource.getEarthSourceBlock(player, selectRange, ClickType.SHIFT_DOWN); + + if (EarthAbility.getMovedEarth().containsKey(b)) + return false; + + if (!isMetal(b)) + return false; + + source = b; + + if (ElementalAbility.isAir(source.getRelative(BlockFace.UP).getType()) && !isMetal(source.getRelative(BlockFace.DOWN))) { + horizontal = true; + } + + return true; + } + + public void raiseBlock(Block b, Vector d) { + Block up = b.getRelative(BlockFace.UP); + Block away = b.getRelative(GeneralMethods.getCardinalDirection(d)); + Block awayup = away.getRelative(BlockFace.UP); + Block deeperb = b.getRelative(BlockFace.DOWN); + Block deepera = away.getRelative(BlockFace.DOWN); + + for (TempBlock tb : tblocks) { + if (!ElementalAbility.isAir(tb.getBlock().getType())) + tb.setType(Material.AIR); + } + + if (!up.getType().isSolid()) { + TempBlock tbu = new TempBlock(up, b.getBlockData()); + tblocks.add(tbu); + } + + if (!awayup.getType().isSolid()) { + TempBlock tbau = new TempBlock(awayup, away.getBlockData()); + tblocks.add(tbau); + } + + if (isMetal(b)) { + TempBlock tbd = new TempBlock(b, Material.AIR.createBlockData()); + tblocks.add(tbd); + } + + if (isMetal(away)) { + TempBlock tba = new TempBlock(away, Material.AIR.createBlockData()); + tblocks.add(tba); + } + + if (isMetal(deeperb)) { + TempBlock tbdb = new TempBlock(deeperb, Material.AIR.createBlockData()); + tblocks.add(tbdb); + } + + if (isMetal(deepera)) { + TempBlock tbda = new TempBlock(deepera, Material.AIR.createBlockData()); + tblocks.add(tbda); + } + + playMetalbendingSound(b.getLocation()); + } + + public void shiftBlock(Block b, Vector d) { + Block under = b.getRelative(BlockFace.DOWN); + Block side = b.getRelative(GeneralMethods.getCardinalDirection(d).getOppositeFace()); + Block underside = under.getRelative(GeneralMethods.getCardinalDirection(d).getOppositeFace()); + + for (TempBlock tb : tblocks) { + if (!ElementalAbility.isAir(tb.getBlock().getType())) + tb.setType(Material.AIR); + } + + if (!side.getType().isSolid()) { + TempBlock tbs = new TempBlock(side, b.getBlockData()); + tblocks.add(tbs); + } + + if (!underside.getType().isSolid()) { + TempBlock tbus = new TempBlock(underside, under.getBlockData()); + tblocks.add(tbus); + } + + if (isMetal(b)) { + TempBlock tb1 = new TempBlock(b, Material.AIR.createBlockData()); + tblocks.add(tb1); + } + + if (isMetal(under)) { + TempBlock tb2 = new TempBlock(under, Material.AIR.createBlockData()); + tblocks.add(tb2); + } + + playMetalbendingSound(b.getLocation()); + } + + private void peelCoil(Block b) { + Block under = b.getRelative(BlockFace.DOWN); + + if (length <= 0) + return; + + if (!b.getType().isSolid()) { + TempBlock tbb = new TempBlock(b, Material.IRON_BLOCK.createBlockData()); + tblocks.add(tbb); + } + + else + stopCoil = true; + + if (!under.getType().isSolid()) { + TempBlock tbu = new TempBlock(under, Material.IRON_BLOCK.createBlockData()); + tblocks.add(tbu); + } + + else + stopCoil = true; + + playMetalbendingSound(b.getLocation()); + + length--; + } + + public static void startShred(Player player) { + if (hasAbility(player, MetalShred.class)) { + getAbility(player, MetalShred.class).startShred(); + } + } + + private void startShred() { + started = true; + } + + public static void extend(Player player) { + if (hasAbility(player, MetalShred.class)) { + getAbility(player, MetalShred.class).extend(); + } + } + + private void extend() { + if (extending) { + extending = false; + return; + } + + if (!stop) + return; + + lastExtendTime = System.currentTimeMillis(); + fullLength = length; + if (lastBlock != null) + lastBlock = lastBlock.getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(player.getLocation(), lastBlock.getLocation())).getOppositeFace()); + else { + return; + } + extending = true; + } + + @Override + public void progress() { + if (!player.isOnline() || player.isDead()) { + remove(); + return; + } + + if (!bPlayer.canBendIgnoreCooldowns(this)) { + remove(); + return; + } + + if (!player.isSprinting()) { + if (started) + stop = true; + } + + if (!horizontal && stop && !stopCoil && extending && System.currentTimeMillis() > lastExtendTime + extendTick) { + lastExtendTime = System.currentTimeMillis(); + if (length > 0) { + + Block b = lastBlock.getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(lastBlock.getLocation(), GeneralMethods.getTargetedLocation(player, fullLength)))); + + peelCoil(b); + + for (Entity e : GeneralMethods.getEntitiesAroundPoint(b.getLocation(), 2)) { + if (!(e instanceof LivingEntity) || e.getEntityId() == player.getEntityId()) { + continue; + } + if (RegionProtection.isRegionProtected(this, e.getLocation()) || ((e instanceof Player) && Commands.invincible.contains(e.getName()))) { + continue; + } + DamageHandler.damageEntity(e, damage, this); + GeneralMethods.setVelocity(this, e, e.getVelocity().add(player.getLocation().getDirection().add(new Vector(0, 0.1, 0)))); + } + + lastBlock = b; + } + + return; + } + + if (stop || !started) + return; + + Block b; + + if (lastBlock != null) { + b = lastBlock.getRelative(GeneralMethods.getCardinalDirection(player.getLocation().getDirection())); + } + + else { + b = source.getRelative(GeneralMethods.getCardinalDirection(player.getLocation().getDirection())); + } + + if (!isMetal(b)) { + if (!ElementalAbility.isAir(b.getType())) { + remove(); + } + return; + } + + if (b.getLocation().getX() == player.getLocation().getBlockX() || b.getLocation().getZ() == player.getLocation().getBlockZ()) { + if (horizontal) + raiseBlock(b, GeneralMethods.getDirection(player.getLocation(), b.getLocation())); + else + shiftBlock(b, GeneralMethods.getDirection(player.getLocation(), b.getLocation())); + + length++; + lastBlock = b; + } + } + + private void revertAll() { + for (TempBlock tb : tblocks) { + tb.revertBlock(); + } + } + + @Override + public void remove() { + revertAll(); + super.remove(); + } + + @Override + public long getCooldown() { + return 0; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "MetalShred"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MetalShred.Description"); + } + + public int getSelectRange() { + return selectRange; + } + + public void setSelectRange(int selectRange) { + this.selectRange = selectRange; + } + + public int getExtendTick() { + return extendTick; + } + + public void setExtendTick(int extendTick) { + this.extendTick = extendTick; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public boolean isHorizontal() { + return horizontal; + } + + public void setHorizontal(boolean horizontal) { + this.horizontal = horizontal; + } + + @Override + public boolean isStarted() { + return started; + } + + public void setStarted(boolean started) { + this.started = started; + } + + public boolean isStop() { + return stop; + } + + public void setStop(boolean stop) { + this.stop = stop; + } + + public boolean isStopCoil() { + return stopCoil; + } + + public void setStopCoil(boolean stopCoil) { + this.stopCoil = stopCoil; + } + + public boolean isExtending() { + return extending; + } + + public void setExtending(boolean extending) { + this.extending = extending; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getFullLength() { + return fullLength; + } + + public void setFullLength(int fullLength) { + this.fullLength = fullLength; + } + + public long getLastExtendTime() { + return lastExtendTime; + } + + public void setLastExtendTime(long lastExtendTime) { + this.lastExtendTime = lastExtendTime; + } + + public Block getSource() { + return source; + } + + public void setSource(Block source) { + this.source = source; + } + + public Block getLastBlock() { + return lastBlock; + } + + public void setLastBlock(Block lastBlock) { + this.lastBlock = lastBlock; + } + + public List getTblocks() { + return tblocks; + } + + @Override + public void load() {} - @Override - public void stop() {} + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.MetalShred.Enabled"); - } -} + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.MetalShred.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/MudSurge.java b/src/com/jedk1/jedcore/ability/earthbending/MudSurge.java index 30e57f6..f704193 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/MudSurge.java +++ b/src/com/jedk1/jedcore/ability/earthbending/MudSurge.java @@ -17,7 +17,6 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.TempBlock; - import com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.Material; @@ -36,619 +35,648 @@ import java.util.stream.Collectors; public class MudSurge extends EarthAbility implements AddonAbility { - private int prepareRange; - private int blindChance; - private int blindTicks; - private boolean multipleHits; - @Attribute(Attribute.DAMAGE) - private double damage; - private int waves; - private int waterSearchRadius; - private boolean wetSource; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute("CollisionRadius") - private double collisionRadius; - - public static int surgeInterval = 300; - public static int mudPoolRadius = 2; - public static Set mudTypes = new HashSet<>(); - - static { - mudTypes.addAll(Arrays.asList(Material.SAND, Material.RED_SAND, Material.CLAY, Material.TERRACOTTA, Material.BLACK_TERRACOTTA, Material.BLUE_TERRACOTTA, - Material.BROWN_TERRACOTTA, Material.CYAN_TERRACOTTA, Material.GRAY_TERRACOTTA, Material.GREEN_TERRACOTTA, - Material.LIGHT_BLUE_TERRACOTTA, Material.LIGHT_GRAY_TERRACOTTA, Material.LIME_TERRACOTTA, - Material.MAGENTA_TERRACOTTA, Material.ORANGE_TERRACOTTA, Material.PINK_TERRACOTTA, - Material.PURPLE_TERRACOTTA, Material.RED_TERRACOTTA, Material.WHITE_TERRACOTTA, Material.YELLOW_TERRACOTTA, - Material.GRASS_BLOCK, Material.DIRT, Material.MYCELIUM, Material.COARSE_DIRT, - Material.SOUL_SAND, Material.SOUL_SOIL, Material.RED_SANDSTONE, Material.SANDSTONE, Material.CHISELED_SANDSTONE, - Material.CHISELED_RED_SANDSTONE, Material.SMOOTH_SANDSTONE, Material.SMOOTH_RED_SANDSTONE, Material.CUT_SANDSTONE, - Material.CUT_RED_SANDSTONE)); - if (GeneralMethods.getMCVersion() >= 1170) { - mudTypes.add(Material.getMaterial("ROOTED_DIRT")); - } - if (GeneralMethods.getMCVersion() >= 1190) { - mudTypes.add(Material.getMaterial("MUD")); - mudTypes.add(Material.getMaterial("MUDDY_MANGROVE_ROOTS")); - mudTypes.add(Material.getMaterial("PACKED_MUD")); - } - } - - private CompositeRemovalPolicy removalPolicy; - - private Block source; - - private int wavesOnTheRun = 0; - private boolean mudFormed = false; - private boolean doNotSurge = false; - public boolean started = false; - - private final List mudArea = new ArrayList<>(); - private ListIterator mudAreaItr; - private final List mudBlocks = new ArrayList<>(); - private final List blind = new ArrayList<>(); - private final List affectedEntities = new ArrayList<>(); - - private final List fallingBlocks = new ArrayList<>(); - - private final Random rand = new Random(); - - public MudSurge(Player player) { - super(player); - - if (!bPlayer.canBend(this)) { - return; - } - - if (hasAbility(player, MudSurge.class)) { - MudSurge ms = getAbility(player, MudSurge.class); - if (!ms.hasStarted()) { - ms.remove(); - } else { - return; - } - } - - this.removalPolicy = new CompositeRemovalPolicy(this, - new CannotBendRemovalPolicy(this.bPlayer, this, true, true), - new IsOfflineRemovalPolicy(this.player), - new IsDeadRemovalPolicy(this.player), - new OutOfRangeRemovalPolicy(this.player, 25.0, () -> this.source.getLocation()), - new SwappedSlotsRemovalPolicy<>(bPlayer, MudSurge.class) - ); - - setFields(); - - if (getSource()) { - start(); - if (!isRemoved()) { - loadMudPool(); - } - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - this.removalPolicy.load(config); - - prepareRange = config.getInt("Abilities.Earth.MudSurge.SourceRange"); - blindChance = config.getInt("Abilities.Earth.MudSurge.BlindChance"); - damage = config.getDouble("Abilities.Earth.MudSurge.Damage"); - waves = config.getInt("Abilities.Earth.MudSurge.Waves"); - waterSearchRadius = config.getInt("Abilities.Earth.MudSurge.WaterSearchRadius"); - wetSource = config.getBoolean("Abilities.Earth.MudSurge.WetSourceOnly"); - cooldown = config.getLong("Abilities.Earth.MudSurge.Cooldown"); - blindTicks = config.getInt("Abilities.Earth.MudSurge.BlindTicks"); - multipleHits = config.getBoolean("Abilities.Earth.MudSurge.MultipleHits"); - collisionRadius = config.getDouble("Abilities.Earth.MudSurge.CollisionRadius"); - } - - @Override - public void progress() { - if (removalPolicy.shouldRemove()) { - remove(); - return; - } - - long lastSurgeTime = 0; - if (mudFormed && started && System.currentTimeMillis() > lastSurgeTime + surgeInterval) { - surge(); - affect(); - if (TempFallingBlock.getFromAbility(this).isEmpty()) { - remove(); - return; - } - return; - } - - if (!mudFormed) { - createMudPool(); - } - } - - private boolean getSource() { - Block block = getMudSourceBlock(prepareRange); - - if (block != null) { - if (isMudBlock(block)) { - boolean water = true; - - if (wetSource) { - water = false; - List nearby = GeneralMethods.getBlocksAroundPoint(block.getLocation(), waterSearchRadius); - - for (Block b : nearby) { - if (b.getType() == Material.WATER) { - water = true; - break; - } - } - } - - if (water) { - this.source = block; - return true; - } - } - } - - return false; - } - - private void startSurge() { - started = true; - this.bPlayer.addCooldown(this); - - // Clear out the policies that only apply while sourcing. - this.removalPolicy.removePolicyType(IsDeadRemovalPolicy.class); - this.removalPolicy.removePolicyType(OutOfRangeRemovalPolicy.class); - this.removalPolicy.removePolicyType(SwappedSlotsRemovalPolicy.class); - } - - private boolean hasStarted() { - return this.started; - } - - public static boolean isSurgeBlock(Block block) { - if (block.getType() != Material.BROWN_TERRACOTTA) { - return false; - } - - for (MudSurge surge : CoreAbility.getAbilities(MudSurge.class)) { - if (surge.mudArea.contains(block)) { - return true; - } - } - - return false; - } - - // Returns true if the event should be cancelled. - public static boolean onFallDamage(Player player) { - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - if (bPlayer == null || !bPlayer.hasElement(Element.EARTH)) { - return false; - } - - ConfigurationSection config = JedCoreConfig.getConfig(player); - - boolean fallDamage = config.getBoolean("Abilities.Earth.MudSurge.AllowFallDamage"); - if (fallDamage) { - return false; - } - - Block block = player.getLocation().clone().subtract(0, 0.1, 0).getBlock(); - return isSurgeBlock(block); - } - - public static void mudSurge(Player player) { - if (!hasAbility(player, MudSurge.class)) - return; - - getAbility(player, MudSurge.class).startSurge(); - } - - private Block getMudSourceBlock(int range) { - Block testBlock = GeneralMethods.getTargetedLocation(player, range, ElementalAbility.getTransparentMaterials()).getBlock(); - if (isMudBlock(testBlock)) - return testBlock; - - Location loc = player.getEyeLocation(); - Vector dir = player.getEyeLocation().getDirection().clone().normalize(); - - for (int i = 0; i <= range; i++) { - Block block = loc.clone().add(dir.clone().multiply(i == 0 ? 1 : i)).getBlock(); - if (RegionProtection.isRegionProtected(player, block.getLocation(), this)) - continue; - - if (isMudBlock(block)) - return block; - } - - return null; - } - - private boolean isMudBlock(Block block) { - for (Material mat : mudTypes) { - if (mat.name().equalsIgnoreCase(block.getType().name())) - return true; - } - - return false; - } - - private void createMud(Block block) { - mudBlocks.add(new TempBlock(block, Material.BROWN_TERRACOTTA.createBlockData())); - } - - private void loadMudPool() { - List area = GeneralMethods.getCircle(source.getLocation(), mudPoolRadius, 3, false, true, 0); - - for (Location l : area) { - Block b = l.getBlock(); - - if (isMudBlock(b)) { - if (isTransparent(b.getRelative(BlockFace.UP))) { - boolean water = true; - - if (wetSource) { - water = false; - List nearby = GeneralMethods.getBlocksAroundPoint(l, waterSearchRadius); - - for (Block block : nearby) { - if (block.getType() == Material.WATER) { - water = true; - break; - } - } - } - - if (water) { - mudArea.add(b); - playEarthbendingSound(b.getLocation()); - } - } - } - } - - Collections.shuffle(mudArea); - mudAreaItr = mudArea.listIterator(); - } - - private void createMudPool() { - if (!mudAreaItr.hasNext()) { - mudFormed = true; - return; - } - - Block b = mudAreaItr.next(); - - if (b != null) - createMud(b); - } - - private void revertMudPool() { - for (TempBlock tb : mudBlocks) - tb.revertBlock(); - - mudBlocks.clear(); - } - - private void surge() { - if (wavesOnTheRun >= waves) { - doNotSurge = true; - return; - } - - if (doNotSurge) - return; - - for (TempBlock tb : mudBlocks) { - Vector direction = GeneralMethods.getDirection(tb.getLocation().add(0, 1, 0), GeneralMethods.getTargetedLocation(player, 30)).multiply(0.07); - - double x = rand.nextDouble() / 5; - double z = rand.nextDouble() / 5; - - x = (rand.nextBoolean()) ? -x : x; - z = (rand.nextBoolean()) ? -z : z; - - fallingBlocks.add(new TempFallingBlock(tb.getLocation().add(0.5, 1, 0.5), Material.BROWN_TERRACOTTA.createBlockData(), direction.clone().add(new Vector(x, 0.2, z)), this)); - - playEarthbendingSound(tb.getLocation()); - } - - wavesOnTheRun++; - } - - private void affect() { - for (TempFallingBlock tfb : TempFallingBlock.getFromAbility(this)) { - FallingBlock fb = tfb.getFallingBlock(); - if (fb.isDead()) { - tfb.remove(); - continue; - } - - for (Entity e : GeneralMethods.getEntitiesAroundPoint(fb.getLocation(), 1.5)) { - if (fb.isDead()) { - tfb.remove(); - continue; - } - if (RegionProtection.isRegionProtected(this, e.getLocation()) || ((e instanceof Player) && Commands.invincible.contains(e.getName()))){ - continue; - } - - if (e instanceof LivingEntity) { - if (this.multipleHits || !this.affectedEntities.contains(e)) { - DamageHandler.damageEntity(e, damage, this); - if (!this.multipleHits) { - this.affectedEntities.add(e); - } - } - - if (e instanceof Player) { - if (e.getEntityId() == player.getEntityId()) - continue; - - if (rand.nextInt(100) < blindChance && !blind.contains(e)) { - ((Player) e).addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, this.blindTicks, 2)); - } - - blind.add((Player) e); - } - - e.setVelocity(fb.getVelocity().multiply(0.8)); - tfb.remove(); - } - } - } - } - - @Override - public void remove() { - revertMudPool(); - super.remove(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public List getLocations() { - return fallingBlocks.stream().map(TempFallingBlock::getLocation).collect(Collectors.toList()); - } - - @Override - public void handleCollision(Collision collision) { - CollisionUtil.handleFallingBlockCollisions(collision, fallingBlocks); - } - - @Override - public double getCollisionRadius() { - return collisionRadius; - } - - @Override - public String getName() { - return "MudSurge"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MudSurge.Description"); - } - - public int getPrepareRange() { - return prepareRange; - } - - public void setPrepareRange(int prepareRange) { - this.prepareRange = prepareRange; - } - - public int getBlindChance() { - return blindChance; - } - - public void setBlindChance(int blindChance) { - this.blindChance = blindChance; - } - - public int getBlindTicks() { - return blindTicks; - } - - public void setBlindTicks(int blindTicks) { - this.blindTicks = blindTicks; - } - - public boolean isMultipleHits() { - return multipleHits; - } - - public void setMultipleHits(boolean multipleHits) { - this.multipleHits = multipleHits; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public int getWaves() { - return waves; - } - - public void setWaves(int waves) { - this.waves = waves; - } - - public int getWaterSearchRadius() { - return waterSearchRadius; - } - - public void setWaterSearchRadius(int waterSearchRadius) { - this.waterSearchRadius = waterSearchRadius; - } - - public boolean isWetSource() { - return wetSource; - } - - public void setWetSource(boolean wetSource) { - this.wetSource = wetSource; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public void setCollisionRadius(double collisionRadius) { - this.collisionRadius = collisionRadius; - } - - public static int getSurgeInterval() { - return surgeInterval; - } - - public static void setSurgeInterval(int surgeInterval) { - MudSurge.surgeInterval = surgeInterval; - } - - public static int getMudPoolRadius() { - return mudPoolRadius; - } - - public static void setMudPoolRadius(int mudPoolRadius) { - MudSurge.mudPoolRadius = mudPoolRadius; - } - - public static Material[] getMudTypes() { - return mudTypes.toArray(new Material[0]); - } - - public static Set getMudTypesSet() { - return mudTypes; - } - - public static void setMudTypes(Material[] mudTypes) { - MudSurge.mudTypes.clear(); - MudSurge.mudTypes.addAll(Arrays.asList(mudTypes)); - } - - public CompositeRemovalPolicy getRemovalPolicy() { - return removalPolicy; - } - - public void setRemovalPolicy(CompositeRemovalPolicy removalPolicy) { - this.removalPolicy = removalPolicy; - } - - public void setSource(Block source) { - this.source = source; - } - - public int getWavesOnTheRun() { - return wavesOnTheRun; - } - - public void setWavesOnTheRun(int wavesOnTheRun) { - this.wavesOnTheRun = wavesOnTheRun; - } - - public boolean isMudFormed() { - return mudFormed; - } - - public void setMudFormed(boolean mudFormed) { - this.mudFormed = mudFormed; - } - - public boolean isDoNotSurge() { - return doNotSurge; - } - - public void setDoNotSurge(boolean doNotSurge) { - this.doNotSurge = doNotSurge; - } - - @Override - public boolean isStarted() { - return started; - } - - public void setStarted(boolean started) { - this.started = started; - } - - public List getMudArea() { - return mudArea; - } - - public ListIterator getMudAreaItr() { - return mudAreaItr; - } - - public void setMudAreaItr(ListIterator mudAreaItr) { - this.mudAreaItr = mudAreaItr; - } - - public List getMudBlocks() { - return mudBlocks; - } - - public List getBlind() { - return blind; - } - - public List getAffectedEntities() { - return affectedEntities; - } - - public List getFallingBlocks() { - return fallingBlocks; - } - - @Override - public void load() {} - - @Override - public void stop() {} + private int prepareRange; + private int blindChance; + private int blindTicks; + private boolean multipleHits; + @Attribute(Attribute.DAMAGE) + private double damage; + private int waves; + private int waterSearchRadius; + private boolean wetSource; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute("CollisionRadius") + private double collisionRadius; + + public static int surgeInterval = 300; + public static int mudPoolRadius = 2; + public static Set mudTypes = new HashSet<>(); + private static Material mudType; + + static { + mudType = Material.valueOf("BROWN_TERRACOTTA"); + mudTypes.addAll(Arrays.asList(Material.SAND, Material.RED_SAND, Material.CLAY, Material.TERRACOTTA, Material.BLACK_TERRACOTTA, Material.BLUE_TERRACOTTA, + Material.BROWN_TERRACOTTA, Material.CYAN_TERRACOTTA, Material.GRAY_TERRACOTTA, Material.GREEN_TERRACOTTA, + Material.LIGHT_BLUE_TERRACOTTA, Material.LIGHT_GRAY_TERRACOTTA, Material.LIME_TERRACOTTA, + Material.MAGENTA_TERRACOTTA, Material.ORANGE_TERRACOTTA, Material.PINK_TERRACOTTA, + Material.PURPLE_TERRACOTTA, Material.RED_TERRACOTTA, Material.WHITE_TERRACOTTA, Material.YELLOW_TERRACOTTA, + Material.GRASS_BLOCK, Material.DIRT, Material.MYCELIUM, Material.COARSE_DIRT, + Material.SOUL_SAND, Material.SOUL_SOIL, Material.RED_SANDSTONE, Material.SANDSTONE, Material.CHISELED_SANDSTONE, + Material.CHISELED_RED_SANDSTONE, Material.SMOOTH_SANDSTONE, Material.SMOOTH_RED_SANDSTONE, Material.CUT_SANDSTONE, + Material.CUT_RED_SANDSTONE)); + if (GeneralMethods.getMCVersion() >= 1170) { + mudTypes.add(Material.getMaterial("ROOTED_DIRT")); + } + if (GeneralMethods.getMCVersion() >= 1190) { + mudTypes.add(Material.getMaterial("MUD")); + mudTypes.add(Material.getMaterial("MUDDY_MANGROVE_ROOTS")); + mudTypes.add(Material.getMaterial("PACKED_MUD")); + mudType = Material.valueOf("MUD"); + } + } + + private CompositeRemovalPolicy removalPolicy; + + private Block source; + + private int wavesOnTheRun = 0; + private boolean mudFormed = false; + private boolean doNotSurge = false; + public boolean started = false; + + private final List mudArea = new ArrayList<>(); + private ListIterator mudAreaItr; + private final List mudBlocks = new ArrayList<>(); + private final List blind = new ArrayList<>(); + private final List affectedEntities = new ArrayList<>(); + + private final List fallingBlocks = new ArrayList<>(); + + private final Random rand = new Random(); + + public MudSurge(Player player) { + super(player); + + if (!bPlayer.canBend(this)) { + return; + } + + if (hasAbility(player, MudSurge.class)) { + MudSurge ms = getAbility(player, MudSurge.class); + if (!ms.hasStarted()) { + ms.remove(); + } else { + return; + } + } + + this.removalPolicy = new CompositeRemovalPolicy(this, + new CannotBendRemovalPolicy(this.bPlayer, this, true, true), + new IsOfflineRemovalPolicy(this.player), + new IsDeadRemovalPolicy(this.player), + new OutOfRangeRemovalPolicy(this.player, 25.0, () -> this.source.getLocation()), + new SwappedSlotsRemovalPolicy<>(bPlayer, MudSurge.class) + ); + + setFields(); + + if (getSource()) { + start(); + if (!isRemoved()) { + loadMudPool(); + } + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + this.removalPolicy.load(config); + + prepareRange = config.getInt("Abilities.Earth.MudSurge.SourceRange"); + blindChance = config.getInt("Abilities.Earth.MudSurge.BlindChance"); + damage = config.getDouble("Abilities.Earth.MudSurge.Damage"); + waves = config.getInt("Abilities.Earth.MudSurge.Waves"); + waterSearchRadius = config.getInt("Abilities.Earth.MudSurge.WaterSearchRadius"); + wetSource = config.getBoolean("Abilities.Earth.MudSurge.WetSourceOnly"); + cooldown = config.getLong("Abilities.Earth.MudSurge.Cooldown"); + blindTicks = config.getInt("Abilities.Earth.MudSurge.BlindTicks"); + multipleHits = config.getBoolean("Abilities.Earth.MudSurge.MultipleHits"); + collisionRadius = config.getDouble("Abilities.Earth.MudSurge.CollisionRadius"); + } + + @Override + public void progress() { + if (removalPolicy.shouldRemove()) { + remove(); + return; + } + + long lastSurgeTime = 0; + if (mudFormed && started && System.currentTimeMillis() > lastSurgeTime + surgeInterval) { + surge(); + affect(); + if (TempFallingBlock.getFromAbility(this).isEmpty()) { + remove(); + return; + } + return; + } + + if (!mudFormed) { + createMudPool(); + } + } + + private boolean getSource() { + Block block = getMudSourceBlock(prepareRange); + + if (block != null) { + if (isMudBlock(block)) { + boolean water = true; + + if (wetSource) { + water = false; + List nearby = GeneralMethods.getBlocksAroundPoint(block.getLocation(), waterSearchRadius); + + for (Block b : nearby) { + if (b.getType() == Material.WATER) { + water = true; + break; + } + } + } + + if (water) { + this.source = block; + return true; + } + } + } + + return false; + } + + private boolean isValidMudSource(Block block) { + return block != null && !EarthAbility.getMovedEarth().containsKey(block); + } + + private void startSurge() { + started = true; + this.bPlayer.addCooldown(this); + + // Clear out the policies that only apply while sourcing. + this.removalPolicy.removePolicyType(IsDeadRemovalPolicy.class); + this.removalPolicy.removePolicyType(OutOfRangeRemovalPolicy.class); + this.removalPolicy.removePolicyType(SwappedSlotsRemovalPolicy.class); + } + + private boolean hasStarted() { + return this.started; + } + + public static boolean isSurgeBlock(Block block) { + if (block.getType() != Material.MUD) { + return false; + } + + for (MudSurge surge : CoreAbility.getAbilities(MudSurge.class)) { + if (surge.mudArea.contains(block)) { + return true; + } + } + + return false; + } + + // Returns true if the event should be cancelled. + public static boolean onFallDamage(Player player) { + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); + if (bPlayer == null || !bPlayer.hasElement(Element.EARTH)) { + return false; + } + + ConfigurationSection config = JedCoreConfig.getConfig(player); + + boolean fallDamage = config.getBoolean("Abilities.Earth.MudSurge.AllowFallDamage"); + if (fallDamage) { + return false; + } + + Block block = player.getLocation().clone().subtract(0, 0.1, 0).getBlock(); + return isSurgeBlock(block); + } + + public static void mudSurge(Player player) { + if (!hasAbility(player, MudSurge.class)) + return; + + getAbility(player, MudSurge.class).startSurge(); + } + + private Block getMudSourceBlock(int range) { + Block testBlock = GeneralMethods.getTargetedLocation(player, range, ElementalAbility.getTransparentMaterials()).getBlock(); + if (isMudBlock(testBlock)) + return testBlock; + + Location loc = player.getEyeLocation(); + Vector dir = player.getEyeLocation().getDirection().clone().normalize(); + + for (int i = 0; i <= range; i++) { + Block block = loc.clone().add(dir.clone().multiply(i == 0 ? 1 : i)).getBlock(); + if (RegionProtection.isRegionProtected(player, block.getLocation(), this)) + continue; + + if (isMudBlock(block)) + return block; + } + + return null; + } + + private boolean isMudBlock(Block block) { + for (Material mat : mudTypes) { + if (mat.name().equalsIgnoreCase(block.getType().name())) + return true; + } + + return false; + } + + private void createMud(Block block) { + mudBlocks.add(new TempBlock(block, mudType.createBlockData())); + } + + private void loadMudPool() { + List area = GeneralMethods.getCircle(source.getLocation(), mudPoolRadius, 3, false, true, 0); + + for (Location l : area) { + Block b = l.getBlock(); + + if (isMudBlock(b)) { + if (isTransparent(b.getRelative(BlockFace.UP))) { + boolean water = true; + + if (wetSource) { + water = false; + List nearby = GeneralMethods.getBlocksAroundPoint(l, waterSearchRadius); + + for (Block block : nearby) { + if (block.getType() == Material.WATER) { + water = true; + break; + } + } + } + + if (water) { + mudArea.add(b); + playEarthbendingSound(b.getLocation()); + } + } + } + } + + Collections.shuffle(mudArea); + mudAreaItr = mudArea.listIterator(); + } + + private void createMudPool() { + // guard against a null iterator (safety) and handle empty iterator + if (mudAreaItr == null || !mudAreaItr.hasNext()) { + mudFormed = true; + return; + } + + Block b = mudAreaItr.next(); + + if (b != null) + createMud(b); + } + + private void revertMudPool() { + for (TempBlock tb : mudBlocks) + tb.revertBlock(); + + mudBlocks.clear(); + } + + private void surge() { + if (wavesOnTheRun >= waves) { + doNotSurge = true; + return; + } + + if (doNotSurge) + return; + + for (TempBlock tb : mudBlocks) { + Vector direction = GeneralMethods.getDirection(tb.getLocation().add(0, 1, 0), GeneralMethods.getTargetedLocation(player, 30)).multiply(0.07); + + double x = rand.nextDouble() / 5; + double z = rand.nextDouble() / 5; + + x = (rand.nextBoolean()) ? -x : x; + z = (rand.nextBoolean()) ? -z : z; + + fallingBlocks.add(new TempFallingBlock(tb.getLocation().add(0.5, 1, 0.5), mudType.createBlockData(), direction.clone().add(new Vector(x, 0.2, z)), this)); + + playEarthbendingSound(tb.getLocation()); + } + + wavesOnTheRun++; + } + + private void affect() { + // Copy the collection to avoid ConcurrentModificationExceptions if the underlying collection is mutated by tfb.remove() + List tempList = new ArrayList<>(TempFallingBlock.getFromAbility(this)); + + for (TempFallingBlock tfb : tempList) { + FallingBlock fb = tfb.getFallingBlock(); + if (fb == null) { + // Defensive: if falling block not present, ensure TFb is removed from the original collection + try { + tfb.remove(); + } catch (Exception ignored) {} + continue; + } + + if (fb.isDead()) { + // Remove from both TFb internal registration and our local tracking if needed + try { + tfb.remove(); + } catch (Exception ignored) {} + continue; + } + + // Copy entity list as well just in case another plugin modifies entities mid-iteration + List entities = new ArrayList<>(GeneralMethods.getEntitiesAroundPoint(fb.getLocation(), 1.5)); + for (Entity e : entities) { + if (fb.isDead()) { + try { + tfb.remove(); + } catch (Exception ignored) {} + continue; + } + if (RegionProtection.isRegionProtected(this, e.getLocation()) || ((e instanceof Player) && Commands.invincible.contains(e.getName()))){ + continue; + } + + if (e instanceof LivingEntity) { + if (this.multipleHits || !this.affectedEntities.contains(e)) { + DamageHandler.damageEntity(e, damage, this); + if (!this.multipleHits) { + this.affectedEntities.add(e); + } + } + + if (e instanceof Player) { + if (e.getEntityId() == player.getEntityId()) + continue; + + if (rand.nextInt(100) < blindChance && !blind.contains(e)) { + ((Player) e).addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, this.blindTicks, 2)); + } + + blind.add((Player) e); + } + + // Apply velocity and then remove the falling block (safe because we're iterating a copy) + e.setVelocity(fb.getVelocity().multiply(0.8)); + try { + tfb.remove(); + } catch (Exception ignored) {} + } + } + } + } + + @Override + public void remove() { + revertMudPool(); + super.remove(); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public List getLocations() { + return fallingBlocks.stream().map(TempFallingBlock::getLocation).collect(Collectors.toList()); + } + + @Override + public void handleCollision(Collision collision) { + CollisionUtil.handleFallingBlockCollisions(collision, fallingBlocks); + } + + @Override + public double getCollisionRadius() { + return collisionRadius; + } + + @Override + public String getName() { + return "MudSurge"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.MudSurge.Description"); + } + + public int getPrepareRange() { + return prepareRange; + } + + public void setPrepareRange(int prepareRange) { + this.prepareRange = prepareRange; + } + + public int getBlindChance() { + return blindChance; + } + + public void setBlindChance(int blindChance) { + this.blindChance = blindChance; + } + + public int getBlindTicks() { + return blindTicks; + } + + public void setBlindTicks(int blindTicks) { + this.blindTicks = blindTicks; + } + + public boolean isMultipleHits() { + return multipleHits; + } + + public void setMultipleHits(boolean multipleHits) { + this.multipleHits = multipleHits; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public int getWaves() { + return waves; + } + + public void setWaves(int waves) { + this.waves = waves; + } + + public int getWaterSearchRadius() { + return waterSearchRadius; + } + + public void setWaterSearchRadius(int waterSearchRadius) { + this.waterSearchRadius = waterSearchRadius; + } + + public boolean isWetSource() { + return wetSource; + } + + public void setWetSource(boolean wetSource) { + this.wetSource = wetSource; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public void setCollisionRadius(double collisionRadius) { + this.collisionRadius = collisionRadius; + } + + public static int getSurgeInterval() { + return surgeInterval; + } + + public static void setSurgeInterval(int surgeInterval) { + MudSurge.surgeInterval = surgeInterval; + } + + public static int getMudPoolRadius() { + return mudPoolRadius; + } + + public static void setMudPoolRadius(int mudPoolRadius) { + MudSurge.mudPoolRadius = mudPoolRadius; + } + + public static Material[] getMudTypes() { + return mudTypes.toArray(new Material[0]); + } + + public static Set getMudTypesSet() { + return mudTypes; + } + + public static void setMudTypes(Material[] mudTypes) { + MudSurge.mudTypes.clear(); + MudSurge.mudTypes.addAll(Arrays.asList(mudTypes)); + } + + public CompositeRemovalPolicy getRemovalPolicy() { + return removalPolicy; + } + + public void setRemovalPolicy(CompositeRemovalPolicy removalPolicy) { + this.removalPolicy = removalPolicy; + } + + public void setSource(Block source) { + this.source = source; + } + + public int getWavesOnTheRun() { + return wavesOnTheRun; + } + + public void setWavesOnTheRun(int wavesOnTheRun) { + this.wavesOnTheRun = wavesOnTheRun; + } + + public boolean isMudFormed() { + return mudFormed; + } + + public void setMudFormed(boolean mudFormed) { + this.mudFormed = mudFormed; + } + + public boolean isDoNotSurge() { + return doNotSurge; + } + + public void setDoNotSurge(boolean doNotSurge) { + this.doNotSurge = doNotSurge; + } + + @Override + public boolean isStarted() { + return started; + } + + public void setStarted(boolean started) { + this.started = started; + } + + public List getMudArea() { + return mudArea; + } + + public ListIterator getMudAreaItr() { + return mudAreaItr; + } + + public void setMudAreaItr(ListIterator mudAreaItr) { + this.mudAreaItr = mudAreaItr; + } + + public List getMudBlocks() { + return mudBlocks; + } + + public List getBlind() { + return blind; + } + + public List getAffectedEntities() { + return affectedEntities; + } + + public List getFallingBlocks() { + return fallingBlocks; + } + + @Override + public void load() {} + + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.MudSurge.Enabled"); - } + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.MudSurge.Enabled"); + } } diff --git a/src/com/jedk1/jedcore/ability/earthbending/SandBlast.java b/src/com/jedk1/jedcore/ability/earthbending/SandBlast.java index cef279e..7c00908 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/SandBlast.java +++ b/src/com/jedk1/jedcore/ability/earthbending/SandBlast.java @@ -4,17 +4,15 @@ import com.jedk1.jedcore.configuration.JedCoreConfig; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.ElementalAbility; import com.projectkorra.projectkorra.ability.SandAbility; import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.earthbending.passive.DensityShift; import com.projectkorra.projectkorra.region.RegionProtection; -import com.projectkorra.projectkorra.util.BlockSource; -import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.TempBlock; - import com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.Material; @@ -22,11 +20,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; @@ -39,341 +33,344 @@ public class SandBlast extends SandAbility implements AddonAbility { - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.SELECT_RANGE) - private double sourceRange; - @Attribute(Attribute.RANGE) - private int range; - @Attribute("MaxShots") - private int maxBlasts; - @Attribute(Attribute.DAMAGE) - private static double damage; - - private Block source; - private BlockData sourceData; - private int blasts; - private boolean blasting; - private Vector direction; - private TempBlock tempBlock; - private final List affectedEntities = new ArrayList<>(); - private final List fallingBlocks = new ArrayList<>(); - - Random rand = new Random(); - - public SandBlast(Player player) { - super(player); - - if (!bPlayer.canBend(this)) { - return; - } - - if (hasAbility(player, SandBlast.class)) { - SandBlast sb = getAbility(player, SandBlast.class); - sb.remove(); - } - - setFields(); - if (prepare()) { - start(); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Earth.SandBlast.Cooldown"); - sourceRange = config.getDouble("Abilities.Earth.SandBlast.SourceRange"); - range = config.getInt("Abilities.Earth.SandBlast.Range"); - maxBlasts = config.getInt("Abilities.Earth.SandBlast.MaxSandBlocks"); - damage = config.getDouble("Abilities.Earth.SandBlast.Damage"); - } - - private boolean prepare() { - source = BlockSource.getEarthSourceBlock(player, sourceRange, ClickType.SHIFT_DOWN); - - if (source != null) { - if (isSand(source) && ElementalAbility.isAir(source.getRelative(BlockFace.UP).getType())) { - this.sourceData = source.getBlockData().clone(); - if (DensityShift.isPassiveSand(source)) { - DensityShift.revertSand(source); - } - tempBlock = new TempBlock(source, Material.SANDSTONE.createBlockData()); - return true; - } - } - return false; - } - - @Override - public void progress() { - if (!hasAbility(player, SandBlast.class)) { - return; - } - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - if (player.getWorld() != source.getWorld()) { - remove(); - return; - } - if (blasting) { - if (blasts <= maxBlasts) { - blastSand(); - blasts++; - } else { - if (TempFallingBlock.getFromAbility(this).isEmpty()) { - remove(); - return; - } - } - affect(); - } - } - - @Override - public void remove() { - if (this.tempBlock != null) { - this.tempBlock.revertBlock(); - } - super.remove(); - } - - public static void blastSand(Player player) { - if (hasAbility(player, SandBlast.class)) { - SandBlast sb = getAbility(player, SandBlast.class); - if (sb.blasting) { - return; - } - sb.blastSand(); - } - } - - private void blastSand() { - if (!blasting) { - blasting = true; - direction = GeneralMethods.getDirection(source.getLocation().clone().add(0, 1, 0), GeneralMethods.getTargetedLocation(player, range)).multiply(0.07); - this.bPlayer.addCooldown(this); - } - tempBlock.revertBlock(); - - //FallingBlock fblock = source.getWorld().spawnFallingBlock(source.getLocation().clone().add(0, 1, 0), source.getType(), source.getData()); - - if (rand.nextInt(2) == 0) { - DensityShift.playSandbendingSound(source.getLocation().add(0, 1, 0)); - } - - double x = rand.nextDouble() / 10; - double z = rand.nextDouble() / 10; - - x = (rand.nextBoolean()) ? -x : x; - z = (rand.nextBoolean()) ? -z : z; - - //fblock.setVelocity(direction.clone().add(new Vector(x, 0.2, z))); - //fblock.setDropItem(false); - //fblocks.put(fblock, player); - - fallingBlocks.add(new TempFallingBlock(source.getLocation().add(0, 1, 0), sourceData, direction.clone().add(new Vector(x, 0.2, z)), this)); - - } - - public void affect() { - for (TempFallingBlock tfb : TempFallingBlock.getFromAbility(this)) { - FallingBlock fblock = tfb.getFallingBlock(); - if (fblock.isDead()) { - tfb.remove(); - continue; - } - - if (RegionProtection.isRegionProtected(player, fblock.getLocation(), this)) { - tfb.remove(); - continue; - } - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(fblock.getLocation(), 1.5)) { - if (entity instanceof LivingEntity && !(entity instanceof ArmorStand)) { - if (entity == this.player) continue; - if (affectedEntities.contains(entity)) continue; - - if (!entity.isDead()) { - DamageHandler.damageEntity(entity, damage, this); - - affectedEntities.add(entity); - - LivingEntity le = (LivingEntity) entity; - if (le.hasPotionEffect(PotionEffectType.BLINDNESS)) { - le.removePotionEffect(PotionEffectType.BLINDNESS); - } - - le.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 60, 1)); - } - } - } - } - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public List getLocations() { - return fallingBlocks.stream().map(TempFallingBlock::getLocation).collect(Collectors.toList()); - } - - @Override - public void handleCollision(Collision collision) { - if (collision.isRemovingFirst()) { - Location location = collision.getLocationFirst(); - - Optional collidedObject = fallingBlocks.stream().filter(temp -> temp.getLocation().equals(location)).findAny(); - - if (collidedObject.isPresent()) { - fallingBlocks.remove(collidedObject.get()); - collidedObject.get().remove(); - } - } - } - - @Override - public String getName() { - return "SandBlast"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.SandBlast.Description"); - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public double getSourceRange() { - return sourceRange; - } - - public void setSourceRange(double sourceRange) { - this.sourceRange = sourceRange; - } - - public int getRange() { - return range; - } - - public void setRange(int range) { - this.range = range; - } - - public int getMaxBlasts() { - return maxBlasts; - } - - public void setMaxBlasts(int maxBlasts) { - this.maxBlasts = maxBlasts; - } - - public static double getDamage() { - return damage; - } - - public static void setDamage(double damage) { - SandBlast.damage = damage; - } - - public Block getSource() { - return source; - } - - public void setSource(Block source) { - this.source = source; - } - - public BlockData getSourceData() { - return sourceData; - } - - public void setSourceData(BlockData sourceData) { - this.sourceData = sourceData; - } - - public int getBlasts() { - return blasts; - } - - public void setBlasts(int blasts) { - this.blasts = blasts; - } - - public boolean isBlasting() { - return blasting; - } - - public void setBlasting(boolean blasting) { - this.blasting = blasting; - } - - public Vector getDirection() { - return direction; - } - - public void setDirection(Vector direction) { - this.direction = direction; - } - - public TempBlock getTempBlock() { - return tempBlock; - } - - public void setTempBlock(TempBlock tempBlock) { - this.tempBlock = tempBlock; - } - - public List getAffectedEntities() { - return affectedEntities; - } - - public List getFallingBlocks() { - return fallingBlocks; - } - - @Override - public void load() {} - - @Override - public void stop() {} + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.SELECT_RANGE) + private double sourceRange; + @Attribute(Attribute.RANGE) + private int range; + @Attribute("MaxShots") + private int maxBlasts; + @Attribute(Attribute.DAMAGE) + private static double damage; + + private Block source; + private BlockData sourceData; + private int blasts; + private boolean blasting; + private Vector direction; + private TempBlock tempBlock; + private final List affectedEntities = new ArrayList<>(); + private final List fallingBlocks = new ArrayList<>(); + + Random rand = new Random(); + + public SandBlast(Player player) { + super(player); + + if (!bPlayer.canBend(this)) { + return; + } + + if (hasAbility(player, SandBlast.class)) { + SandBlast sb = getAbility(player, SandBlast.class); + sb.remove(); + } + + setFields(); + if (prepare()) { + start(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Earth.SandBlast.Cooldown"); + sourceRange = config.getDouble("Abilities.Earth.SandBlast.SourceRange"); + range = config.getInt("Abilities.Earth.SandBlast.Range"); + maxBlasts = config.getInt("Abilities.Earth.SandBlast.MaxSandBlocks"); + damage = config.getDouble("Abilities.Earth.SandBlast.Damage"); + } + + private boolean prepare() { + source = getEarthSourceBlock(sourceRange); + + if (source != null) { + if (EarthAbility.getMovedEarth().containsKey(source)) { + return false; + } + if (isSand(source) && ElementalAbility.isAir(source.getRelative(BlockFace.UP).getType())) { + this.sourceData = source.getBlockData().clone(); + if (DensityShift.isPassiveSand(source)) { + DensityShift.revertSand(source); + } + tempBlock = new TempBlock(source, Material.SANDSTONE.createBlockData()); + return true; + } + } + return false; + } + + @Override + public void progress() { + if (!hasAbility(player, SandBlast.class)) { + return; + } + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + if (player.getWorld() != source.getWorld()) { + remove(); + return; + } + if (blasting) { + if (blasts <= maxBlasts) { + blastSand(); + blasts++; + } else { + if (TempFallingBlock.getFromAbility(this).isEmpty()) { + remove(); + return; + } + } + affect(); + } + } + + @Override + public void remove() { + if (this.tempBlock != null) { + this.tempBlock.revertBlock(); + } + super.remove(); + } + + public static void blastSand(Player player) { + if (hasAbility(player, SandBlast.class)) { + SandBlast sb = getAbility(player, SandBlast.class); + if (sb.blasting) { + return; + } + sb.blastSand(); + } + } + + private void blastSand() { + if (!blasting) { + blasting = true; + direction = GeneralMethods.getDirection(source.getLocation().clone().add(0, 1, 0), GeneralMethods.getTargetedLocation(player, range)).multiply(0.07); + this.bPlayer.addCooldown(this); + } + tempBlock.revertBlock(); + + //FallingBlock fblock = source.getWorld().spawnFallingBlock(source.getLocation().clone().add(0, 1, 0), source.getType(), source.getData()); + + if (rand.nextInt(2) == 0) { + DensityShift.playSandbendingSound(source.getLocation().add(0, 1, 0)); + } + + double x = rand.nextDouble() / 10; + double z = rand.nextDouble() / 10; + + x = (rand.nextBoolean()) ? -x : x; + z = (rand.nextBoolean()) ? -z : z; + + //fblock.setVelocity(direction.clone().add(new Vector(x, 0.2, z))); + //fblock.setDropItem(false); + //fblocks.put(fblock, player); + + fallingBlocks.add(new TempFallingBlock(source.getLocation().add(0, 1, 0), sourceData, direction.clone().add(new Vector(x, 0.2, z)), this)); + + } + + public void affect() { + for (TempFallingBlock tfb : TempFallingBlock.getFromAbility(this)) { + FallingBlock fblock = tfb.getFallingBlock(); + if (fblock.isDead()) { + tfb.remove(); + continue; + } + + if (RegionProtection.isRegionProtected(player, fblock.getLocation(), this)) { + tfb.remove(); + continue; + } + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(fblock.getLocation(), 1.5)) { + if (entity instanceof LivingEntity && !(entity instanceof ArmorStand)) { + if (entity == this.player) continue; + if (affectedEntities.contains(entity)) continue; + + if (!entity.isDead()) { + DamageHandler.damageEntity(entity, damage, this); + + affectedEntities.add(entity); + + LivingEntity le = (LivingEntity) entity; + if (le.hasPotionEffect(PotionEffectType.BLINDNESS)) { + le.removePotionEffect(PotionEffectType.BLINDNESS); + } + + le.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 60, 1)); + } + } + } + } + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public List getLocations() { + return fallingBlocks.stream().map(TempFallingBlock::getLocation).collect(Collectors.toList()); + } + + @Override + public void handleCollision(Collision collision) { + if (collision.isRemovingFirst()) { + Location location = collision.getLocationFirst(); + + Optional collidedObject = fallingBlocks.stream().filter(temp -> temp.getLocation().equals(location)).findAny(); + + if (collidedObject.isPresent()) { + fallingBlocks.remove(collidedObject.get()); + collidedObject.get().remove(); + } + } + } + + @Override + public String getName() { + return "SandBlast"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.SandBlast.Description"); + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public double getSourceRange() { + return sourceRange; + } + + public void setSourceRange(double sourceRange) { + this.sourceRange = sourceRange; + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public int getMaxBlasts() { + return maxBlasts; + } + + public void setMaxBlasts(int maxBlasts) { + this.maxBlasts = maxBlasts; + } + + public static double getDamage() { + return damage; + } + + public static void setDamage(double damage) { + SandBlast.damage = damage; + } + + public Block getSource() { + return source; + } + + public void setSource(Block source) { + this.source = source; + } + + public BlockData getSourceData() { + return sourceData; + } + + public void setSourceData(BlockData sourceData) { + this.sourceData = sourceData; + } + + public int getBlasts() { + return blasts; + } + + public void setBlasts(int blasts) { + this.blasts = blasts; + } + + public boolean isBlasting() { + return blasting; + } + + public void setBlasting(boolean blasting) { + this.blasting = blasting; + } + + public Vector getDirection() { + return direction; + } + + public void setDirection(Vector direction) { + this.direction = direction; + } + + public TempBlock getTempBlock() { + return tempBlock; + } + + public void setTempBlock(TempBlock tempBlock) { + this.tempBlock = tempBlock; + } + + public List getAffectedEntities() { + return affectedEntities; + } + + public List getFallingBlocks() { + return fallingBlocks; + } + + @Override + public void load() {} + + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.SandBlast.Enabled"); - } -} + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.SandBlast.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/combo/Crevice.java b/src/com/jedk1/jedcore/ability/earthbending/combo/Crevice.java index f4e22c4..a26ae34 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/combo/Crevice.java +++ b/src/com/jedk1/jedcore/ability/earthbending/combo/Crevice.java @@ -11,8 +11,6 @@ import com.projectkorra.projectkorra.ability.util.ComboUtil; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.region.RegionProtection; -import com.projectkorra.projectkorra.util.ClickType; - import com.projectkorra.projectkorra.util.TempBlock; import org.bukkit.Location; import org.bukkit.Material; @@ -28,343 +26,349 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class Crevice extends EarthAbility implements AddonAbility, ComboAbility { - - @Attribute(Attribute.RANGE) - private double range; - private long regenDelay; - @Attribute("Depth") - private int randomDepth; - private int avatarDepth; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - - private Location origin; - private Location location; - private Vector direction; - private double travelled; - private boolean skip; - - private final List> columns = new ArrayList<>(); - - private final Random rand = new Random(); - - public Crevice(Player player) { - super(player); - if (!bPlayer.canBendIgnoreBinds(this)) { - return; - } - - setFields(); - createInstance(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - range = config.getDouble("Abilities.Earth.EarthCombo.Crevice.Range"); - regenDelay = config.getLong("Abilities.Earth.EarthCombo.Crevice.RevertDelay"); - randomDepth = config.getInt("Abilities.Earth.EarthCombo.Crevice.Depth"); - avatarDepth = config.getInt("Abilities.Earth.EarthCombo.Crevice.AvatarStateDepth"); - cooldown = config.getLong("Abilities.Earth.EarthCombo.Crevice.Cooldown"); - } - - private void createInstance() { - origin = player.getTargetBlock(null, 6).getLocation(); - if (isEarthbendable(origin.getBlock())) { - Location tempLoc = player.getLocation().clone(); - tempLoc.setPitch(0); - direction = tempLoc.getDirection().clone(); - origin.setDirection(tempLoc.getDirection()); - location = origin.clone(); - if (bPlayer.isAvatarState()) { - randomDepth = avatarDepth; - } - - start(); - if (!isRemoved()) { - bPlayer.addCooldown(this); - } - } - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - prepareRevert(); - remove(); - return; - } - if (travelled >= range || skip) { - if (System.currentTimeMillis() > getStartTime() + regenDelay) { - prepareRevert(); - remove(); - return; - } - return; - } - advanceCrevice(); - } - - @Override - public void remove() { - prepareRevert(); - super.remove(); - } - - public static void closeCrevice(Player player) { - Block target = player.getTargetBlock(null, 10); - for (Block near : GeneralMethods.getBlocksAroundPoint(target.getLocation(), 2)) { - for (Crevice c : getAbilities(Crevice.class)) { - for (List tbs : c.columns) { - for (TempBlock tb : tbs) { - if (near.getLocation().equals(tb.getLocation())) { - c.prepareRevert(); - c.remove(); - return; - } - } - } - } - } - } - - private void advanceCrevice() { - switch (rand.nextInt(2)) { - case 0: - if (location.getYaw() <= origin.getYaw()) { - location.setYaw(location.getYaw() + 40); - direction = location.getDirection().clone(); - } - break; - case 1: - if (location.getYaw() >= origin.getYaw()) { - location.setYaw(location.getYaw() - 40); - direction = location.getDirection().clone(); - } - break; - default: - direction = location.getDirection().clone(); - break; - } - - Location tempLoc = location.clone(); - location = location.add(direction.multiply(1)); - playEarthbendingSound(tempLoc); - location.getWorld().playSound(location, Sound.ENTITY_ZOMBIE_BREAK_WOODEN_DOOR, (float) 0.5, (float) 0.5); - if (skip) { - return; - } - - travelled++; - if (travelled >= range) - return; - - if (RegionProtection.isRegionProtected(player, location, "RaiseEarth")) { - return; - } - - if (!isTransparent(location.getBlock().getRelative(BlockFace.UP))) { - location.add(0, 1, 0); - if (!isTransparent(location.getBlock().getRelative(BlockFace.UP)) || !isEarthbendable(location.getBlock())) { - skip = true; - return; - } - } else if (isTransparent(location.getBlock()) || !isEarthbendable(location.getBlock())) { - location.subtract(0, 1, 0); - if (isTransparent(location.getBlock()) || !isEarthbendable(location.getBlock())) { - skip = true; - return; - } - } - - removePillar(tempLoc, randInt(randomDepth + 1 - 2, randomDepth + 1 + 2)); - removePillar(GeneralMethods.getRightSide(tempLoc, 1), randInt(randomDepth - 1, randomDepth + 1)); - removePillar(GeneralMethods.getLeftSide(tempLoc, 1), randInt(randomDepth - 1, randomDepth + 1)); - } - - private int randInt(int min, int max) { - return rand.nextInt(max - min) + min; - } - - private void removePillar(Location location, int depth) { - List blocks = new ArrayList<>(); - Location tempLoc = location.clone().getBlock().getLocation(); - tempLoc.add(0, 1, 0); - for (int i = 0; i < depth + 1; i++) { - if (tempLoc.getY() < Objects.requireNonNull(tempLoc.getWorld()).getMinHeight() || tempLoc.getY() > tempLoc.getWorld().getMaxHeight()) { - break; - } - if (RegionProtection.isRegionProtected(player, tempLoc, this)) { - continue; - } - if (i == 0 && !isTransparent(tempLoc.getBlock())) { - continue; - } - if (i > 0 && !isEarthbendable(tempLoc.getBlock())) { - continue; - } - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(tempLoc, 1)) { - entity.setVelocity(new Vector(0, -0.75, 0)); - } - - - blocks.add(new TempBlock(tempLoc.getBlock(), Material.AIR.createBlockData())); - tempLoc.subtract(0, 1, 0); - } - - Collections.reverse(blocks); - - columns.add(blocks); - } - - private void prepareRevert() { - for (int i = 0; i < columns.size(); ++i) { - List tbs = columns.get(i); - for (TempBlock tb : tbs) { - tb.revertBlock(); - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(tb.getLocation(), 1)) { - entity.setVelocity(new Vector(0, 0.7, 0)); - } - new RegenTempBlock(tb.getBlock(), Material.AIR, Material.AIR.createBlockData(), i * 50L); - } - } - columns.clear(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public String getName() { - return "Crevice"; - } - - @Override - public boolean isHiddenAbility() { - return false; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return false; - } - - @Override - public Object createNewComboInstance(Player player) { - return new Crevice(player); - } - - @Override - public ArrayList getCombination() { - return ComboUtil.generateCombinationFromList(this, JedCoreConfig.getConfig(player).getStringList("Abilities.Earth.EarthCombo.Crevice.Combination")); - } - - @Override - public String getInstructions() { - return JedCoreConfig.getConfig(player).getString("Abilities.Earth.EarthCombo.Crevice.Instructions"); - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthCombo.Crevice.Description"); - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - public double getRange() { - return range; - } - - public void setRange(double range) { - this.range = range; - } - - public long getRegenDelay() { - return regenDelay; - } - - public void setRegenDelay(long regenDelay) { - this.regenDelay = regenDelay; - } - - public int getDepth() { - return randomDepth; - } - - public void setDepth(int depth) { - this.randomDepth = depth; - } - - public int getAvatarDepth() { - return avatarDepth; - } - - public void setAvatarDepth(int avatarDepth) { - this.avatarDepth = avatarDepth; - } - - public Location getOrigin() { - return origin; - } - - public void setOrigin(Location origin) { - this.origin = origin; - } - - public Vector getDirection() { - return direction; - } - - public void setDirection(Vector direction) { - this.direction = direction; - } - - public double getDistanceTravelled() { - return travelled; - } - - public void setDistanceTravelled(double travelled) { - this.travelled = travelled; - } - - public List> getColumns() { - return columns; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.EarthCombo.Crevice.Enabled"); - } -} + private final List> columns = new ArrayList<>(); + + private Location origin; + private Location location; + private Vector direction; + private double travelled; + private boolean skip; + private int avatarDepth; + private long regenDelay; + + @Attribute(Attribute.RANGE) + private double range; + @Attribute("Depth") + private int randomDepth; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + + public Crevice(Player player) { + super(player); + + if (!bPlayer.canBendIgnoreBinds(this)) { + return; + } + + setFields(); + + createInstance(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + range = config.getDouble("Abilities.Earth.EarthCombo.Crevice.Range"); + regenDelay = config.getLong("Abilities.Earth.EarthCombo.Crevice.RevertDelay"); + randomDepth = config.getInt("Abilities.Earth.EarthCombo.Crevice.Depth"); + avatarDepth = config.getInt("Abilities.Earth.EarthCombo.Crevice.AvatarStateDepth"); + cooldown = config.getLong("Abilities.Earth.EarthCombo.Crevice.Cooldown"); + } + + private void createInstance() { + origin = player.getTargetBlock(null, 6).getLocation(); + + if (isEarthbendable(origin.getBlock()) && !EarthAbility.getMovedEarth().containsKey(origin.getBlock())) { + Location tempLoc = player.getLocation().clone(); + tempLoc.setPitch(0); + + direction = tempLoc.getDirection().clone(); + origin.setDirection(tempLoc.getDirection()); // todo + location = origin.clone(); + + if (bPlayer.isAvatarState()) { + randomDepth = avatarDepth; + } + + start(); + + if (!isRemoved()) { + bPlayer.addCooldown(this); + } + } + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + prepareRevert(); + remove(); + return; + } + + if (travelled >= range || skip) { + if (System.currentTimeMillis() > getStartTime() + regenDelay) { + prepareRevert(); + remove(); + return; + } + return; + } + + advanceCrevice(); + } + + @Override + public void remove() { + prepareRevert(); + super.remove(); + } + + public static void closeCrevice(Player player) { + Block target = player.getTargetBlock(null, 10); + + for (Block near : GeneralMethods.getBlocksAroundPoint(target.getLocation(), 2)) { + for (Crevice c : getAbilities(Crevice.class)) { + for (List tbs : c.columns) { + for (TempBlock tb : tbs) { + if (near.getLocation().equals(tb.getLocation())) { + c.prepareRevert(); + c.remove(); + return; + } + } + } + } + } + } + + private void advanceCrevice() { + switch (ThreadLocalRandom.current().nextInt(2)) { + case 0: + if (location.getYaw() <= origin.getYaw()) { + location.setYaw(location.getYaw() + 40); + direction = location.getDirection().clone(); + } + break; + case 1: + if (location.getYaw() >= origin.getYaw()) { + location.setYaw(location.getYaw() - 40); + direction = location.getDirection().clone(); + } + break; + default: + direction = location.getDirection().clone(); + break; + } + + Location tempLoc = location.clone(); + location = location.add(direction.multiply(1)); + playEarthbendingSound(tempLoc); + location.getWorld().playSound(location, Sound.ENTITY_ZOMBIE_BREAK_WOODEN_DOOR, (float) 0.5, (float) 0.5); + if (skip) { + return; + } + + travelled++; + if (travelled >= range) + return; + + if (RegionProtection.isRegionProtected(player, location, "RaiseEarth")) { + return; + } + + if (!isTransparent(location.getBlock().getRelative(BlockFace.UP))) { + location.add(0, 1, 0); + if (!isTransparent(location.getBlock().getRelative(BlockFace.UP)) || !isEarthbendable(location.getBlock())) { + skip = true; + return; + } + } else if (isTransparent(location.getBlock()) || !isEarthbendable(location.getBlock())) { + location.subtract(0, 1, 0); + if (isTransparent(location.getBlock()) || !isEarthbendable(location.getBlock())) { + skip = true; + return; + } + } + + removePillar(tempLoc, randInt(randomDepth + 1 - 2, randomDepth + 1 + 2)); + removePillar(GeneralMethods.getRightSide(tempLoc, 1), randInt(randomDepth - 1, randomDepth + 1)); + removePillar(GeneralMethods.getLeftSide(tempLoc, 1), randInt(randomDepth - 1, randomDepth + 1)); + } + + private int randInt(int min, int max) { + return ThreadLocalRandom.current().nextInt(max - min) + min; // todo: look into the necessity of this helper + } + + private void removePillar(Location location, int depth) { + List blocks = new ArrayList<>(); + Location tempLoc = location.clone().getBlock().getLocation(); + tempLoc.add(0, 1, 0); + for (int i = 0; i < depth + 1; i++) { + if (tempLoc.getY() < Objects.requireNonNull(tempLoc.getWorld()).getMinHeight() || tempLoc.getY() > tempLoc.getWorld().getMaxHeight()) { + break; + } + if (RegionProtection.isRegionProtected(player, tempLoc, this)) { + continue; + } + if (i == 0 && !isTransparent(tempLoc.getBlock())) { + continue; + } + if (i > 0 && (!isEarthbendable(tempLoc.getBlock()) || EarthAbility.getMovedEarth().containsKey(tempLoc.getBlock()))) { + continue; + } + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(tempLoc, 1)) { + entity.setVelocity(new Vector(0, -0.75, 0)); + } + + + blocks.add(new TempBlock(tempLoc.getBlock(), Material.AIR.createBlockData())); + tempLoc.subtract(0, 1, 0); + } + + Collections.reverse(blocks); + + columns.add(blocks); + } + + private void prepareRevert() { + for (int i = 0; i < columns.size(); ++i) { + List tbs = columns.get(i); + for (TempBlock tb : tbs) { + tb.revertBlock(); + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(tb.getLocation(), 1)) { + entity.setVelocity(new Vector(0, 0.7, 0)); + } + new RegenTempBlock(tb.getBlock(), Material.AIR, Material.AIR.createBlockData(), i * 50L); + } + } + columns.clear(); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getName() { + return "Crevice"; + } + + @Override + public boolean isHiddenAbility() { + return false; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return false; + } + + @Override + public Object createNewComboInstance(Player player) { + return new Crevice(player); + } + + @Override + public ArrayList getCombination() { + return ComboUtil.generateCombinationFromList(this, JedCoreConfig.getConfig(player).getStringList("Abilities.Earth.EarthCombo.Crevice.Combination")); + } + + @Override + public String getInstructions() { + return JedCoreConfig.getConfig(player).getString("Abilities.Earth.EarthCombo.Crevice.Instructions"); + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthCombo.Crevice.Description"); + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + public double getRange() { + return range; + } + + public void setRange(double range) { + this.range = range; + } + + public long getRegenDelay() { + return regenDelay; + } + + public void setRegenDelay(long regenDelay) { + this.regenDelay = regenDelay; + } + + public int getDepth() { + return randomDepth; + } + + public void setDepth(int depth) { + this.randomDepth = depth; + } + + public int getAvatarDepth() { + return avatarDepth; + } + + public void setAvatarDepth(int avatarDepth) { + this.avatarDepth = avatarDepth; + } + + public Location getOrigin() { + return origin; + } + + public void setOrigin(Location origin) { + this.origin = origin; + } + + public Vector getDirection() { + return direction; + } + + public void setDirection(Vector direction) { + this.direction = direction; + } + + public double getDistanceTravelled() { + return travelled; + } + + public void setDistanceTravelled(double travelled) { + this.travelled = travelled; + } + + public List> getColumns() { + return columns; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.EarthCombo.Crevice.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/earthbending/combo/MagmaBlast.java b/src/com/jedk1/jedcore/ability/earthbending/combo/MagmaBlast.java index 55426ba..9bf8012 100644 --- a/src/com/jedk1/jedcore/ability/earthbending/combo/MagmaBlast.java +++ b/src/com/jedk1/jedcore/ability/earthbending/combo/MagmaBlast.java @@ -1,24 +1,17 @@ package com.jedk1.jedcore.ability.earthbending.combo; -import com.jedk1.jedcore.collision.AABB; +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.util.MaterialUtil; -import com.projectkorra.projectkorra.ability.ElementalAbility; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.*; +import com.projectkorra.projectkorra.ability.util.ComboManager.AbilityInformation; import com.projectkorra.projectkorra.ability.util.ComboUtil; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.earthbending.lava.LavaFlow; - -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.ComboAbility; -import com.projectkorra.projectkorra.ability.LavaAbility; -import com.projectkorra.projectkorra.ability.util.ComboManager.AbilityInformation; -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 com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.Material; @@ -27,570 +20,598 @@ import org.bukkit.block.BlockFace; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Entity; +import org.bukkit.entity.FallingBlock; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.util.Vector; import java.util.*; +import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; public class MagmaBlast extends LavaAbility implements AddonAbility, ComboAbility { - private static final int PARTICLE_COUNT = 20; - private static final int RAISE_HEIGHT = 3; - private static final Random rand = new Random(); - - private final Set sources = new HashSet<>(); - private final List blocks = new ArrayList<>(); - private final List firedBlocks = new ArrayList<>(); - - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.DURATION) - private long maxDuration; - private long shotCooldown; - @Attribute("MaxSources") - private int maxSources; - @Attribute(Attribute.SELECT_RANGE) - private int sourceRange; - @Attribute(Attribute.SELECT_RANGE) - private double selectRange; - @Attribute(Attribute.DAMAGE) - private double damage; - private double fireSpeed; - // How far away the player is allowed to be from the sources before the ability is destroyed. - private double maxDistanceFromSources; - private float explosionRadius = 2.0f; - // This will destroy the instance if LavaFlow is on cooldown. - private boolean requireLavaFlow; - private boolean playerCollisions; - private boolean entitySelection; - - private Location origin; - private int counter; - private long canLavaFlowTime; - private long lastShot; - private boolean stopFiring; - - public MagmaBlast(Player player) { - super(player); - setFields(); - - if (!bPlayer.canBendIgnoreBinds(this)) { - return; - } - - origin = player.getLocation().clone(); - - if (raiseSources()) { - start(); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - maxSources = config.getInt("Abilities.Earth.EarthCombo.MagmaBlast.MaxShots"); - sourceRange = config.getInt("Abilities.Earth.EarthCombo.MagmaBlast.SearchRange"); - damage = config.getDouble("Abilities.Earth.EarthCombo.MagmaBlast.ImpactDamage"); - cooldown = config.getInt("Abilities.Earth.EarthCombo.MagmaBlast.Cooldown"); - requireLavaFlow = config.getBoolean("Abilities.Earth.EarthCombo.MagmaBlast.RequireLavaFlow"); - playerCollisions = config.getBoolean("Abilities.Earth.EarthCombo.MagmaBlast.PlayerCollisions"); - entitySelection = config.getBoolean("Abilities.Earth.EarthCombo.MagmaBlast.EntitySelection"); - selectRange = config.getDouble("Abilities.Earth.EarthCombo.MagmaBlast.SelectRange"); - explosionRadius = (float) config.getDouble("Abilities.Earth.EarthCombo.MagmaBlast.ExplosionRadius"); - fireSpeed = config.getDouble("Abilities.Earth.EarthCombo.MagmaBlast.FireSpeed"); - maxDuration = config.getLong("Abilities.Earth.EarthCombo.MagmaBlast.MaxDuration"); - maxDistanceFromSources = config.getLong("Abilities.Earth.EarthCombo.MagmaBlast.MaxDistanceFromSources"); - shotCooldown = config.getLong("Abilities.Earth.EarthCombo.MagmaBlast.ShotCooldown"); - } - - // Select random nearby earth blocks as sources and raise them in the air. - private boolean raiseSources() { - List potentialBlocks = GeneralMethods.getBlocksAroundPoint(origin, sourceRange).stream().filter(ElementalAbility::isEarth).collect(Collectors.toList()); - - Collections.shuffle(potentialBlocks); - - for (Block newSource : potentialBlocks) { - if (!isValidSource(newSource)) continue; - - sources.add(new TempFallingBlock(newSource.getLocation().add(0, 1, 0), Material.NETHERRACK.createBlockData(), new Vector(0, 0.9, 0), this)); - - if (sources.size() >= maxSources) { - break; - } - } - - return !sources.isEmpty(); - } - - // Checks to make sure the source block has room to fly upwards. - private boolean isValidSource(Block block) { - for (int i = 0; i <= RAISE_HEIGHT; ++i) { - if (!MaterialUtil.isTransparent(block.getRelative(BlockFace.UP, i + 1)) || block.isLiquid()) { - return false; - } - } - - return true; - } - - public boolean shouldBlockLavaFlow() { - long time = System.currentTimeMillis(); - return time < canLavaFlowTime; - } - - @Override - public void progress() { - stopFiring = false; - if (player == null || !player.isOnline() || player.isDead()) { - remove(); - return; - } - - if (System.currentTimeMillis() > this.getStartTime() + maxDuration) { - remove(); - return; - } - - if (!bPlayer.canBendIgnoreBinds(this) || !(bPlayer.getBoundAbility() instanceof LavaFlow)) { - remove(); - return; - } - - if (requireLavaFlow && !bPlayer.canBend(getAbility("LavaFlow"))) { - remove(); - return; - } - - displayAnimation(); - handleSources(); - - if (playerCollisions) { - doPlayerCollisions(); - } - - if (sources.isEmpty() && firedBlocks.isEmpty() && blocks.isEmpty()) { - remove(); - return; - } - - if (hasBlocks() && this.player.getLocation().distanceSquared(origin) > maxDistanceFromSources * maxDistanceFromSources) { - remove(); - } - } - - @Override - public void remove() { - bPlayer.addCooldown(this); - super.remove(); - - for (TempFallingBlock ftb : sources) { - ftb.remove(); - } - - for (TempBlock tb : blocks) { - tb.revertBlock(); - } - - for (TempFallingBlock tfb : firedBlocks) { - tfb.remove(); - } - } - - private void handleSources() { - if (sources.isEmpty()) return; - - for (Iterator iter = sources.iterator(); iter.hasNext();) { - TempFallingBlock tfb = iter.next(); - - if (tfb.getLocation().getBlockY() >= (origin.getBlockY() + RAISE_HEIGHT)) { - blocks.add(new TempBlock(tfb.getLocation().getBlock(), Material.NETHERRACK.createBlockData())); - iter.remove(); - tfb.remove(); - } - } - } - - private void displayAnimation() { - if (++counter == 3) { - counter = 0; - } else { - return; - } - - for (Iterator iterator = firedBlocks.iterator(); iterator.hasNext();) { - TempFallingBlock tfb = iterator.next(); - - if (!tfb.getFallingBlock().isDead()) { - playParticles(tfb.getLocation()); - } else { - tfb.remove(); - iterator.remove(); - } - } - - for (TempBlock tb : blocks) { - playParticles(tb.getLocation()); - } - } - - private void doPlayerCollisions() { - for (Iterator iterator = firedBlocks.iterator(); iterator.hasNext();) { - TempFallingBlock tfb = iterator.next(); - - boolean didExplode = false; - - for (Entity e : GeneralMethods.getEntitiesAroundPoint(tfb.getLocation(), this.explosionRadius)) { - if (!(e instanceof LivingEntity)) continue; - if (e == this.player) continue; - - if (blast(tfb, true)) { - didExplode = true; - } - } - - if (didExplode) { - tfb.remove(); - iterator.remove(); - } - } - } - - private void playParticles(Location location) { - location.add(.5,.5,.5); - ParticleEffect.LAVA.display(location, 2, Math.random(), Math.random(), Math.random(), 0f); - ParticleEffect.SMOKE_NORMAL.display(location, 2, Math.random(), Math.random(), Math.random(), 0f); - for (int i = 0; i < 10; i++) { - GeneralMethods.displayColoredParticle("FFA400", getOffsetLocation(location, 2)); - GeneralMethods.displayColoredParticle("FF8C00", getOffsetLocation(location, 2)); - } - } - - // Returns true if any source blocks still exist. Returns false is all of the source blocks have been fired. - public boolean hasBlocks() { - return !sources.isEmpty() || !blocks.isEmpty(); - } - - private Location getOffsetLocation(Location loc, double offset) { - return loc.clone().add((float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset)); - } - - public static void performAction(Player player) { - MagmaBlast mb = getAbility(player, MagmaBlast.class); - - if (mb != null) { - mb.performAction(); - } - } - - private void performAction() { - long time = System.currentTimeMillis(); - - if (blocks.isEmpty() || stopFiring || time < lastShot + shotCooldown) return; - - Location target = null; - - if (entitySelection) { - Entity targetEntity = GeneralMethods.getTargetedEntity(player, selectRange); - - if (targetEntity instanceof LivingEntity) { - target = ((LivingEntity) targetEntity).getEyeLocation(); - } - } - - if (target == null) { - target = GeneralMethods.getTargetedLocation(player, selectRange, Material.NETHERRACK); - } - - TempBlock tb = getClosestSource(target); - - if (tb == null) return; - - stopFiring = true; - canLavaFlowTime = time + 1000; - blocks.remove(tb); - - Vector direction = GeneralMethods.getDirection(tb.getLocation().clone().add(0.5f, 0.5f, 0.5f), target).normalize(); - - tb.revertBlock(); - - firedBlocks.add(new TempFallingBlock(tb.getLocation(), Material.NETHERRACK.createBlockData(), direction.multiply(fireSpeed), this, true)); - lastShot = time; - } - - // Get the closest fireable source block to the target location. - private TempBlock getClosestSource(Location target) { - double distanceSq = Double.MAX_VALUE; - TempBlock closest = null; - - for (TempBlock tempBlock : blocks) { - double currentDistSq = tempBlock.getLocation().distanceSquared(target); - - if (currentDistSq < distanceSq) { - distanceSq = currentDistSq; - closest = tempBlock; - } - } - - return closest; - } - - public static void blast(TempFallingBlock tfb) { - blast(tfb, false); - } - - public static boolean blast(TempFallingBlock tfb, boolean entityCollision) { - MagmaBlast mb = (MagmaBlast) tfb.getAbility(); - Location location = tfb.getLocation().clone().add(0.5, 0.5, 0.5); - - float radius = mb.explosionRadius; - - boolean didHit = false; - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, radius)) { - if (!(entity instanceof LivingEntity)) continue; - - if (entity instanceof Player) { - AABB entityBounds = AABB.PlayerBounds.at(entity.getLocation().toVector()); - AABB blockBounds = AABB.BlockBounds.at(tfb.getLocation().toVector()); - - if (entityBounds.intersects(blockBounds)) { - DamageHandler.damageEntity(entity, mb.getDamage(), mb); - didHit = true; - } - } else { - DamageHandler.damageEntity(entity, mb.getDamage(), mb); - didHit = true; - } - } - - if (entityCollision && !didHit) { - return false; - } - - float speed = 0.1f; - ParticleEffect.FLAME.display(location, PARTICLE_COUNT, randomBinomial(radius), randomBinomial(radius), randomBinomial(radius), speed); - ParticleEffect.SMOKE_LARGE.display(location, PARTICLE_COUNT, randomBinomial(radius), randomBinomial(radius), randomBinomial(radius), speed); - ParticleEffect.FIREWORKS_SPARK.display(location, PARTICLE_COUNT, randomBinomial(radius), randomBinomial(radius), randomBinomial(radius), speed); - ParticleEffect.SMOKE_LARGE.display(location, PARTICLE_COUNT, randomBinomial(radius), randomBinomial(radius), randomBinomial(radius), speed); - - location.getWorld().playSound(location, (rand.nextBoolean()) ? Sound.ENTITY_FIREWORK_ROCKET_BLAST : Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, 1f, 1f); - location.getWorld().playSound(location, (rand.nextBoolean()) ? Sound.ENTITY_FIREWORK_ROCKET_TWINKLE : Sound.ENTITY_FIREWORK_ROCKET_TWINKLE_FAR, 1f, 1f); - - if (!entityCollision) { - mb.firedBlocks.remove(tfb); - } - - return true; - } - - // Generates a random number between -max and max. - private static float randomBinomial(float max) { - return (rand.nextFloat() * max) - (rand.nextFloat() * max); - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "MagmaBlast"; - } - - @Override - public boolean isHiddenAbility() { - return false; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return false; - } - - @Override - public Object createNewComboInstance(Player player) { - return new MagmaBlast(player); - } - - @Override - public ArrayList getCombination() { - return ComboUtil.generateCombinationFromList(this, JedCoreConfig.getConfig(player).getStringList("Abilities.Earth.EarthCombo.MagmaBlast.Combination")); - } - - @Override - public String getInstructions() { - return JedCoreConfig.getConfig(player).getString("Abilities.Earth.EarthCombo.MagmaBlast.Instructions"); - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthCombo.MagmaBlast.Description"); - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - public Set getSources() { - return sources; - } - - public List getBlocks() { - return blocks; - } - - public List getFiredBlocks() { - return firedBlocks; - } - - public long getMaxDuration() { - return maxDuration; - } - - public void setMaxDuration(long maxDuration) { - this.maxDuration = maxDuration; - } - - public long getShotCooldown() { - return shotCooldown; - } - - public void setShotCooldown(long shotCooldown) { - this.shotCooldown = shotCooldown; - } - - public int getMaxSources() { - return maxSources; - } - - public void setMaxSources(int maxSources) { - this.maxSources = maxSources; - } - - public int getSourceRange() { - return sourceRange; - } - - public void setSourceRange(int sourceRange) { - this.sourceRange = sourceRange; - } - - public double getSelectRange() { - return selectRange; - } - - public void setSelectRange(double selectRange) { - this.selectRange = selectRange; - } - - public double getFireSpeed() { - return fireSpeed; - } - - public void setFireSpeed(double fireSpeed) { - this.fireSpeed = fireSpeed; - } - - public double getMaxDistanceFromSources() { - return maxDistanceFromSources; - } - - public void setMaxDistanceFromSources(double maxDistanceFromSources) { - this.maxDistanceFromSources = maxDistanceFromSources; - } - - public float getExplosionRadius() { - return explosionRadius; - } - - public void setExplosionRadius(float explosionRadius) { - this.explosionRadius = explosionRadius; - } - - public boolean isRequireLavaFlow() { - return requireLavaFlow; - } - - public void setRequireLavaFlow(boolean requireLavaFlow) { - this.requireLavaFlow = requireLavaFlow; - } - - public boolean isPlayerCollisions() { - return playerCollisions; - } - - public void setPlayerCollisions(boolean playerCollisions) { - this.playerCollisions = playerCollisions; - } - - public boolean isEntitySelection() { - return entitySelection; - } - - public void setEntitySelection(boolean entitySelection) { - this.entitySelection = entitySelection; - } + private static final int PARTICLE_COUNT = 20; + private static final int RAISE_HEIGHT = 3; + + private final Set sources = new HashSet<>(); + private final List blocks = new ArrayList<>(); + private final List firedBlocks = new ArrayList<>(); + + private double fireSpeed; + // How far away the player is allowed to be from the sources before the ability is destroyed. + private double maxDistanceFromSources; + private float explosionRadius = 2.0f; + // This will destroy the instance if LavaFlow is on cooldown. + private boolean requireLavaFlow; + private boolean playerCollisions; + private boolean entitySelection; + private Location origin; + private int counter; + private long canLavaFlowTime; + private long lastShot; + private boolean stopFiring; + private long shotCooldown; + + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.DURATION) + private long maxDuration; + @Attribute("MaxSources") + private int maxSources; + @Attribute(Attribute.SELECT_RANGE) + private int sourceRange; + @Attribute(Attribute.SELECT_RANGE) + private double selectRange; + @Attribute(Attribute.DAMAGE) + private double damage; + + public MagmaBlast(Player player) { + super(player); + setFields(); + + if (!bPlayer.canBendIgnoreBinds(this)) { + return; + } + + origin = player.getLocation().clone(); + + if (raiseSources()) { + start(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + maxSources = config.getInt("Abilities.Earth.EarthCombo.MagmaBlast.MaxShots"); + sourceRange = config.getInt("Abilities.Earth.EarthCombo.MagmaBlast.SearchRange"); + damage = config.getDouble("Abilities.Earth.EarthCombo.MagmaBlast.ImpactDamage"); + cooldown = config.getInt("Abilities.Earth.EarthCombo.MagmaBlast.Cooldown"); + requireLavaFlow = config.getBoolean("Abilities.Earth.EarthCombo.MagmaBlast.RequireLavaFlow"); + playerCollisions = config.getBoolean("Abilities.Earth.EarthCombo.MagmaBlast.PlayerCollisions"); + entitySelection = config.getBoolean("Abilities.Earth.EarthCombo.MagmaBlast.EntitySelection"); + selectRange = config.getDouble("Abilities.Earth.EarthCombo.MagmaBlast.SelectRange"); + explosionRadius = (float) config.getDouble("Abilities.Earth.EarthCombo.MagmaBlast.ExplosionRadius"); + fireSpeed = config.getDouble("Abilities.Earth.EarthCombo.MagmaBlast.FireSpeed"); + maxDuration = config.getLong("Abilities.Earth.EarthCombo.MagmaBlast.MaxDuration"); + maxDistanceFromSources = config.getLong("Abilities.Earth.EarthCombo.MagmaBlast.MaxDistanceFromSources"); + shotCooldown = config.getLong("Abilities.Earth.EarthCombo.MagmaBlast.ShotCooldown"); + } + + // Select random nearby earth blocks as sources and raise them in the air. + private boolean raiseSources() { + List potentialBlocks = GeneralMethods.getBlocksAroundPoint(origin, sourceRange).stream().filter(ElementalAbility::isEarth).collect(Collectors.toList()); + + Collections.shuffle(potentialBlocks); + + for (Block newSource : potentialBlocks) { + if (!isValidSource(newSource)) continue; + + newSource.getWorld().playSound(newSource.getLocation(), Sound.ENTITY_GHAST_SHOOT, 0.8f, 0.3f); + sources.add(new TempFallingBlock(newSource.getLocation().add(0, 1, 0), Material.MAGMA_BLOCK.createBlockData(), new Vector(0, 0.9, 0), this)); + + if (sources.size() >= maxSources) { + break; + } + } + + return !sources.isEmpty(); + } + + // Checks to make sure the source block has room to fly upwards. + private boolean isValidSource(Block block) { + for (int i = 0; i <= RAISE_HEIGHT; ++i) { + if (!MaterialUtil.isTransparent(block.getRelative(BlockFace.UP, i + 1)) || block.isLiquid()) { + return false; + } + } + + return true; + } + + public boolean shouldBlockLavaFlow() { + long time = System.currentTimeMillis(); + return time < canLavaFlowTime; + } + + @Override + public void progress() { + stopFiring = false; + if (player == null || !player.isOnline() || player.isDead()) { + remove(); + return; + } + + if (System.currentTimeMillis() > this.getStartTime() + maxDuration) { + remove(); + return; + } + + if (!bPlayer.canBendIgnoreBinds(this) || !(bPlayer.getBoundAbility() instanceof LavaFlow)) { + remove(); + return; + } + + if (requireLavaFlow && !bPlayer.canBend(getAbility("LavaFlow"))) { + remove(); + return; + } + + displayAnimation(); + handleSources(); + + if (playerCollisions) { + doPlayerCollisions(); + } + + if (sources.isEmpty() && firedBlocks.isEmpty() && blocks.isEmpty()) { + remove(); + return; + } + + if (hasBlocks() && this.player.getLocation().distanceSquared(origin) > maxDistanceFromSources * maxDistanceFromSources) { + remove(); + } + } + + @Override + public void remove() { + bPlayer.addCooldown(this); + super.remove(); + + for (TempFallingBlock ftb : sources) { + ftb.remove(); + } + + for (TempBlock tb : blocks) { + tb.revertBlock(); + } + + for (TempFallingBlock tfb : firedBlocks) { + tfb.remove(); + } + } + + private void handleSources() { + if (sources.isEmpty()) return; + + for (Iterator iter = sources.iterator(); iter.hasNext();) { + TempFallingBlock tfb = iter.next(); + + if (tfb.getLocation().getBlockY() >= (origin.getBlockY() + RAISE_HEIGHT)) { + blocks.add(new TempBlock(tfb.getLocation().getBlock(), Material.MAGMA_BLOCK.createBlockData())); + iter.remove(); + tfb.remove(); + } + } + } + + private void displayAnimation() { + if (++counter == 3) { + counter = 0; + } else { + return; + } + + for (Iterator iterator = firedBlocks.iterator(); iterator.hasNext();) { + TempFallingBlock tfb = iterator.next(); + + if (!tfb.getFallingBlock().isDead()) { + playParticles(tfb.getLocation()); + } else { + tfb.remove(); + iterator.remove(); + } + } + + for (TempBlock tb : blocks) playParticles(tb.getLocation()); + } + + private void doPlayerCollisions() { + List blocksCopy = new ArrayList<>(firedBlocks); + + for (TempFallingBlock tfb : blocksCopy) { + if (!firedBlocks.contains(tfb)) continue; + + boolean didExplode = false; + + for (Entity e : GeneralMethods.getEntitiesAroundPoint(tfb.getLocation(), this.explosionRadius)) { + if (!(e instanceof LivingEntity)) continue; + if (e == this.player) continue; + + if (blast(tfb, true)) { + didExplode = true; + } + } + + if (didExplode) { + firedBlocks.remove(tfb); + } + } + } + + private void playParticles(Location location) { + location.add(.5,.5,.5); + + ParticleEffect.LAVA.display(location, 2, Math.random(), Math.random(), Math.random(), 0f); + ParticleEffect.SMOKE_NORMAL.display(location, 2, Math.random(), Math.random(), Math.random(), 0f); + + for (int i = 0; i < 10; i++) { + GeneralMethods.displayColoredParticle("FFA400", getOffsetLocation(location, 2)); + GeneralMethods.displayColoredParticle("FF8C00", getOffsetLocation(location, 2)); + } + } + + // Returns true if any source blocks still exist. Returns false is all of the source blocks have been fired. + public boolean hasBlocks() { + return !sources.isEmpty() || !blocks.isEmpty(); + } + + private Location getOffsetLocation(Location loc, double offset) { + return loc.clone().add((float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset)); + } + + public static void performAction(Player player) { + MagmaBlast mb = getAbility(player, MagmaBlast.class); + + if (mb != null) { + mb.performAction(); + } + } + + private void performAction() { + long time = System.currentTimeMillis(); + + if (blocks.isEmpty() || stopFiring || time < lastShot + shotCooldown) return; + + Location target = null; + + if (entitySelection) { + Entity targetEntity = GeneralMethods.getTargetedEntity(player, selectRange); + + if (targetEntity instanceof LivingEntity) { + target = ((LivingEntity) targetEntity).getEyeLocation(); + } + } + + if (target == null) { + target = GeneralMethods.getTargetedLocation(player, selectRange, Material.MAGMA_BLOCK); + } + + TempBlock tb = getClosestSource(target); + + if (tb == null) return; + + stopFiring = true; + canLavaFlowTime = time + 1000; + blocks.remove(tb); + + Vector direction = GeneralMethods.getDirection(tb.getLocation().clone().add(0.5f, 0.5f, 0.5f), target).normalize(); + + tb.revertBlock(); + + FallingBlock fallingBlock = tb.getLocation().getWorld().spawnFallingBlock( + tb.getLocation().clone().add(0.5, 0.5, 0.5), + Material.MAGMA_BLOCK.createBlockData() + ); + + fallingBlock.setTicksLived(Integer.MAX_VALUE); + fallingBlock.setMetadata("magmablast", new FixedMetadataValue(JedCore.plugin, "1")); + fallingBlock.setDropItem(false); + fallingBlock.setCancelDrop(true); + + TempFallingBlock tfb = new TempFallingBlock(tb.getLocation(), Material.MAGMA_BLOCK.createBlockData(), direction.multiply(fireSpeed), this, true); + firedBlocks.add(tfb); + + lastShot = time; + } + + // Get the closest fireable source block to the target location. + private TempBlock getClosestSource(Location target) { + double distanceSq = Double.MAX_VALUE; + TempBlock closest = null; + + for (TempBlock tempBlock : blocks) { + Block block = tempBlock.getLocation().getBlock(); + if (EarthAbility.getMovedEarth().containsKey(block)) { + continue; + } + double currentDistSq = tempBlock.getLocation().distanceSquared(target); + + if (currentDistSq < distanceSq) { + distanceSq = currentDistSq; + closest = tempBlock; + } + } + + return closest; + } + + public static void blast(TempFallingBlock tfb) { + blast(tfb, false); + } + + public static boolean blast(TempFallingBlock tfb, boolean entityCollision) { + MagmaBlast mb = (MagmaBlast) tfb.getAbility(); + Location location = tfb.getLocation().clone().add(0.5, 0.5, 0.5); + + Block hitBlock = location.getBlock(); + if (hitBlock.getType().isSolid()) { + blastEffects(location, mb); + tfb.remove(); + mb.firedBlocks.remove(tfb); + return true; + } + + float radius = mb.explosionRadius; + boolean didHit = false; + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, radius)) { + if (!(entity instanceof LivingEntity)) continue; + if (entity == mb.player) continue; + + DamageHandler.damageEntity(entity, mb.getDamage(), mb); + ((LivingEntity) entity).setNoDamageTicks(0); + didHit = true; + } + + if (didHit || entityCollision) { + blastEffects(location, mb); + tfb.remove(); + mb.firedBlocks.remove(tfb); + return true; + } + + return false; + } + + private static void blastEffects(Location location, MagmaBlast mb) { + float radius = mb.explosionRadius; + float speed = 0.1f; + + ParticleEffect.FLAME.display(location, PARTICLE_COUNT, randomBinomial(radius), randomBinomial(radius), randomBinomial(radius), speed); + ParticleEffect.SMOKE_LARGE.display(location, PARTICLE_COUNT, randomBinomial(radius), randomBinomial(radius), randomBinomial(radius), speed); + ParticleEffect.FIREWORKS_SPARK.display(location, PARTICLE_COUNT, randomBinomial(radius), randomBinomial(radius), randomBinomial(radius), speed); + + ThreadLocalRandom rand = ThreadLocalRandom.current(); + + location.getWorld().playSound(location, + (rand.nextBoolean()) ? Sound.ENTITY_FIREWORK_ROCKET_BLAST : Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, + 1f, 1f); + location.getWorld().playSound(location, + (rand.nextBoolean()) ? Sound.ENTITY_FIREWORK_ROCKET_TWINKLE : Sound.ENTITY_FIREWORK_ROCKET_TWINKLE_FAR, + 1f, 1f); + } + + // Generates a random number between -max and max. + private static float randomBinomial(float max) { + ThreadLocalRandom rand = ThreadLocalRandom.current(); + return (rand.nextFloat() * max) - (rand.nextFloat() * max); + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "MagmaBlast"; + } + + @Override + public boolean isHiddenAbility() { + return false; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return false; + } + + @Override + public Object createNewComboInstance(Player player) { + return new MagmaBlast(player); + } + + @Override + public ArrayList getCombination() { + return ComboUtil.generateCombinationFromList(this, JedCoreConfig.getConfig(player).getStringList("Abilities.Earth.EarthCombo.MagmaBlast.Combination")); + } + + @Override + public String getInstructions() { + return JedCoreConfig.getConfig(player).getString("Abilities.Earth.EarthCombo.MagmaBlast.Instructions"); + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Earth.EarthCombo.MagmaBlast.Description"); + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + public Set getSources() { + return sources; + } + + public List getBlocks() { + return blocks; + } + + public List getFiredBlocks() { + return firedBlocks; + } + + public long getMaxDuration() { + return maxDuration; + } + + public void setMaxDuration(long maxDuration) { + this.maxDuration = maxDuration; + } + + public long getShotCooldown() { + return shotCooldown; + } + + public void setShotCooldown(long shotCooldown) { + this.shotCooldown = shotCooldown; + } + + public int getMaxSources() { + return maxSources; + } + + public void setMaxSources(int maxSources) { + this.maxSources = maxSources; + } + + public int getSourceRange() { + return sourceRange; + } + + public void setSourceRange(int sourceRange) { + this.sourceRange = sourceRange; + } + + public double getSelectRange() { + return selectRange; + } + + public void setSelectRange(double selectRange) { + this.selectRange = selectRange; + } + + public double getFireSpeed() { + return fireSpeed; + } + + public void setFireSpeed(double fireSpeed) { + this.fireSpeed = fireSpeed; + } + + public double getMaxDistanceFromSources() { + return maxDistanceFromSources; + } + + public void setMaxDistanceFromSources(double maxDistanceFromSources) { + this.maxDistanceFromSources = maxDistanceFromSources; + } + + public float getExplosionRadius() { + return explosionRadius; + } + + public void setExplosionRadius(float explosionRadius) { + this.explosionRadius = explosionRadius; + } + + public boolean isRequireLavaFlow() { + return requireLavaFlow; + } + + public void setRequireLavaFlow(boolean requireLavaFlow) { + this.requireLavaFlow = requireLavaFlow; + } + + public boolean isPlayerCollisions() { + return playerCollisions; + } + + public void setPlayerCollisions(boolean playerCollisions) { + this.playerCollisions = playerCollisions; + } + + public boolean isEntitySelection() { + return entitySelection; + } + + public void setEntitySelection(boolean entitySelection) { + this.entitySelection = entitySelection; + } - public Location getOrigin() { - return origin; - } + public Location getOrigin() { + return origin; + } - public void setOrigin(Location origin) { - this.origin = origin; - } + public void setOrigin(Location origin) { + this.origin = origin; + } - public long getCanLavaFlowTime() { - return canLavaFlowTime; - } + public long getCanLavaFlowTime() { + return canLavaFlowTime; + } - public void setCanLavaFlowTime(long canLavaFlowTime) { - this.canLavaFlowTime = canLavaFlowTime; - } + public void setCanLavaFlowTime(long canLavaFlowTime) { + this.canLavaFlowTime = canLavaFlowTime; + } - public long getLastShotTime() { - return lastShot; - } + public long getLastShotTime() { + return lastShot; + } - public void setLastShotTime(long lastShot) { - this.lastShot = lastShot; - } + public void setLastShotTime(long lastShot) { + this.lastShot = lastShot; + } - @Override - public void load() {} + @Override + public void load() {} - @Override - public void stop() {} + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Earth.EarthCombo.MagmaBlast.Enabled"); - } + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Earth.EarthCombo.MagmaBlast.Enabled"); + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/firebending/Combustion.java b/src/com/jedk1/jedcore/ability/firebending/Combustion.java index d4cefcc..cbad36d 100644 --- a/src/com/jedk1/jedcore/ability/firebending/Combustion.java +++ b/src/com/jedk1/jedcore/ability/firebending/Combustion.java @@ -7,11 +7,10 @@ import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.policies.removal.*; import com.jedk1.jedcore.util.FireTick; -import com.jedk1.jedcore.util.LightManager; import com.jedk1.jedcore.util.MaterialUtil; import com.jedk1.jedcore.util.RegenTempBlock; -import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.Element.SubElement; +import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.AirAbility; import com.projectkorra.projectkorra.ability.CombustionAbility; @@ -22,10 +21,7 @@ import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Sound; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Entity; @@ -33,552 +29,594 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; +import java.util.stream.Collectors; public class Combustion extends CombustionAbility implements AddonAbility { - private State state; - private Location location; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - private CompositeRemovalPolicy removalPolicy; - - public Combustion(Player player) { - super(player); - - if (!isEnabled()) return; - - if (this.player == null || !bPlayer.canBend(this) || !bPlayer.canCombustionbend()) { - return; - } - - if (hasAbility(player, Combustion.class)) { - Combustion c = getAbility(player, Combustion.class); - if (c.state instanceof ChargeState) - return; - } - - setFields(); - - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Fire.Combustion.Cooldown"); - - this.location = null; - this.state = new ChargeState(); - - this.removalPolicy = new CompositeRemovalPolicy(this, - new CannotBendRemovalPolicy(this.bPlayer, this, true, true), - new IsOfflineRemovalPolicy(this.player), - new IsDeadRemovalPolicy(this.player), - new SwappedSlotsRemovalPolicy<>(bPlayer, Combustion.class) - ); - - this.removalPolicy.load(config, "Abilities.Fire.Combustion"); - } - - @Override - public void progress() { - if (this.removalPolicy.shouldRemove()) { - remove(); - return; - } - - state.update(); - } - - public static void combust(Player player) { - if(hasAbility(player, Combustion.class)) { - Combustion c = getAbility(player, Combustion.class); - - c.selfCombust(); - } - } - - public void selfCombust() { - if (this.state instanceof TravelState) { - this.state = new CombustState(location); - } - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - // Only enable the collision while traveling. - if (state instanceof TravelState) { - return location; - } - - return null; - } - - @Override - public double getCollisionRadius() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getDouble("Abilities.Fire.Combustion.AbilityCollisionRadius"); - } - - @Override - public String getName() { - return "Combustion"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Fire.Combustion.Description"); - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Fire.Combustion.Enabled"); - } - - private interface State { - void update(); - } - - // This is the initial state of Combustion. - // It's used to render the particle ring that happens during charging. - // This state transitions to TravelState if the player stops sneaking after charging is done. - // This state transitions to CombustState if the player takes damage while charging. - private class ChargeState implements State { - private final long startTime; - private int currPoint = (int) player.getLocation().getYaw() + 90; - private final long warmup; - private final double playerStartHealth; - private final boolean instantExplodeIfHit; - - public ChargeState() { - this.startTime = System.currentTimeMillis(); - this.playerStartHealth = player.getHealth(); - - ConfigurationSection config = JedCoreConfig.getConfig(player); - - this.instantExplodeIfHit = config.getBoolean("Abilities.Fire.Combustion.InstantExplodeIfHit"); - this.warmup = config.getLong("Abilities.Fire.Combustion.Warmup"); - } - - @Override - public void update() { - long time = System.currentTimeMillis(); - - boolean charged = time >= this.startTime + warmup; - - if (player.isSneaking()) { - if (!bPlayer.canBendIgnoreBinds(Combustion.this)) { - remove(); - return; - } - - playParticleRing(60, 1.75F, 2); - - if (instantExplodeIfHit && player.getHealth() < playerStartHealth) { - // Remove and combust at player's location - state = new CombustState(player.getLocation(), true); - bPlayer.addCooldown(Combustion.this); - return; - } - - if (charged) { - ParticleEffect.SMOKE_LARGE.display(player.getLocation(), 1, Math.random(), Math.random(), Math.random(), 0.1); - } - } else { - if (charged) { - state = new TravelState(); - bPlayer.addCooldown(Combustion.this); - } else { - remove(); - } - } - } - - private void playParticleRing(int points, float size, int speed) { - for (int i = 0; i < speed; ++i) { - currPoint += 360 / points; - - if (currPoint > 360) { - currPoint = 0; - } - - double angle = currPoint * 3.141592653589793D / 180.0D; - double x = size * Math.cos(angle); - double z = size * Math.sin(angle); - - Location loc = player.getLocation().add(x, 1.0D, z); - playFirebendingParticles(loc, 3, 0.0, 0.0, 0.0); - ParticleEffect.SMOKE_NORMAL.display(loc, 4, 0.0, 0.0, 0.0, 0.01); - JCMethods.emitLight(loc); - } - } - } - - // This state is used after the player releases a charged Combustion. + private State state; + private Location location; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + private CompositeRemovalPolicy removalPolicy; + + private ArrayList skipMaterials; // use a configured list of blocks to skip through + + public Combustion(Player player) { + super(player); + + if (!isEnabled()) return; + + if (this.player == null || !bPlayer.canBend(this) || !bPlayer.canCombustionbend()) { + return; + } + + if (hasAbility(player, Combustion.class)) { + Combustion c = getAbility(player, Combustion.class); + if (c.state instanceof ChargeState) + return; + } + + setFields(); + + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Fire.Combustion.Cooldown"); + + this.location = null; + this.state = new ChargeState(); + + this.removalPolicy = new CompositeRemovalPolicy(this, + new CannotBendRemovalPolicy(this.bPlayer, this, true, true), + new IsOfflineRemovalPolicy(this.player), + new IsDeadRemovalPolicy(this.player), + new SwappedSlotsRemovalPolicy<>(bPlayer, Combustion.class) + ); + + this.removalPolicy.load(config, "Abilities.Fire.Combustion"); + + this.skipMaterials = loadSkipMaterials(); + } + + @Override + public void progress() { + if (this.removalPolicy.shouldRemove()) { + remove(); + return; + } + + state.update(); + } + + public static void combust(Player player) { + if(hasAbility(player, Combustion.class)) { + Combustion c = getAbility(player, Combustion.class); + + c.selfCombust(); + } + } + + public void selfCombust() { + if (this.state instanceof TravelState) { + this.state = new CombustState(location); + } + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + // Only enable the collision while traveling. + if (state instanceof TravelState) { + return location; + } + + return null; + } + + @Override + public double getCollisionRadius() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getDouble("Abilities.Fire.Combustion.AbilityCollisionRadius"); + } + + @Override + public String getName() { + return "Combustion"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Fire.Combustion.Description"); + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Fire.Combustion.Enabled"); + } + + private ArrayList loadSkipMaterials() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + ArrayList skipList = new ArrayList<>(); + + if (config.contains("Abilities.Fire.Combustion.SkipMaterials")) { + List configuredSkipList = config.getStringList("Abilities.Fire.Combustion.SkipMaterials"); + + for (String entry : configuredSkipList) { + if (entry.startsWith("#")) { + String tagName = entry.substring(1).toLowerCase(); + + NamespacedKey tagKey = NamespacedKey.minecraft(tagName); + Tag materialTag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, tagKey, Material.class); + + if (materialTag != null) { + skipList.addAll(materialTag.getValues().stream() + .map(material -> material.name().toLowerCase()) + .collect(Collectors.toList())); + } + } else { + skipList.add(entry.toLowerCase()); + } + } + } + + return skipList; + } + + private interface State { + void update(); + } + + // This is the initial state of Combustion. + // It's used to render the particle ring that happens during charging. + // This state transitions to TravelState if the player stops sneaking after charging is done. + // This state transitions to CombustState if the player takes damage while charging. + private class ChargeState implements State { + private final long startTime; + private int currPoint = (int) player.getLocation().getYaw() + 90; + private final long warmup; + private final double playerStartHealth; + private final boolean instantExplodeIfHit; + + public ChargeState() { + this.startTime = System.currentTimeMillis(); + this.playerStartHealth = player.getHealth(); + + ConfigurationSection config = JedCoreConfig.getConfig(player); + + this.instantExplodeIfHit = config.getBoolean("Abilities.Fire.Combustion.InstantExplodeIfHit"); + this.warmup = config.getLong("Abilities.Fire.Combustion.Warmup"); + } + + @Override + public void update() { + long time = System.currentTimeMillis(); + + boolean charged = time >= this.startTime + warmup; + + if (player.isSneaking()) { + if (!bPlayer.canBendIgnoreBinds(Combustion.this)) { + remove(); + return; + } + + playParticleRing(60, 1.75F, 2); + + if (instantExplodeIfHit && player.getHealth() < playerStartHealth) { + // Remove and combust at player's location + state = new CombustState(player.getLocation(), true); + bPlayer.addCooldown(Combustion.this); + return; + } + + if (charged) { + ParticleEffect.SMOKE_LARGE.display(player.getLocation(), 1, Math.random(), Math.random(), Math.random(), 0.1); + } + } else { + if (charged) { + state = new TravelState(); + bPlayer.addCooldown(Combustion.this); + } else { + remove(); + } + } + } + + private void playParticleRing(int points, float size, int speed) { + for (int i = 0; i < speed; ++i) { + currPoint += 360 / points; + + if (currPoint > 360) { + currPoint = 0; + } + + double angle = currPoint * 3.141592653589793D / 180.0D; + double x = size * Math.cos(angle); + double z = size * Math.sin(angle); + + Location loc = player.getLocation().add(x, 1.0D, z); + playFirebendingParticles(loc, 3, 0.0, 0.0, 0.0); + ParticleEffect.SMOKE_NORMAL.display(loc, 4, 0.0, 0.0, 0.0, 0.01); + JCMethods.emitLight(loc); + } + } + } + + // This state is used after the player releases a charged Combustion. // It's used for moving and rendering the projectile. // This state transitions to CombustState when it collides with terrain or an entity. - private class TravelState implements State { - private Vector direction; - private final int range; - private final double speed; - private final boolean explodeOnDeath; - private final double entityCollisionRadius; - private double distanceTraveled; - - public TravelState() { - removalPolicy.removePolicyType(SwappedSlotsRemovalPolicy.class); - - Location origin = player.getEyeLocation().clone(); - origin.setY(origin.getY() - 0.8D); - location = origin.clone(); - - ConfigurationSection config = JedCoreConfig.getConfig(player); - - range = config.getInt("Abilities.Fire.Combustion.Range"); - speed = config.getDouble("Abilities.Fire.Combustion.Speed"); - explodeOnDeath = config.getBoolean("Abilities.Fire.Combustion.ExplodeOnDeath"); - entityCollisionRadius = config.getDouble("Abilities.Fire.Combustion.EntityCollisionRadius"); - - if (explodeOnDeath) { - removalPolicy.removePolicyType(CannotBendRemovalPolicy.class); - removalPolicy.removePolicyType(IsDeadRemovalPolicy.class); - } - - direction = player.getEyeLocation().getDirection().normalize(); - distanceTraveled = 0; - } - - @Override - public void update() { - if (explodeOnDeath && player.isDead()) { - state = new CombustState(location); - return; - } - - // Manually handle the region protection check because the CannotBendRemovalPolicy no longer checks it - // when explodeOnDeath is true. This stops players from firing Combustion and then walking into a - // protected area. - if (explodeOnDeath) { - if (RegionProtection.isRegionProtected(Combustion.this, player.getLocation())) { - remove(); - return; - } - } - - if (distanceTraveled >= range) { - remove(); - return; - } - - travel(); - } - - private void travel() { - double stepDistance = speed; - - for (int i = 0; i < (int) (speed * 5); ++i) { - render(); - - Sphere collider = new Sphere(location.toVector(), entityCollisionRadius); - - boolean hit = CollisionDetector.checkEntityCollisions(player, collider, (entity) -> { - location = entity.getLocation(); - state = new CombustState(location); - return true; - }); - - if (hit) { - return; - } - - if (!MaterialUtil.isTransparent(location.getBlock()) || isWater(location.getBlock())) { - state = new CombustState(location); - return; - } - - direction = player.getEyeLocation().getDirection().normalize(); - location = location.add(direction.clone().multiply(stepDistance)); - - distanceTraveled += stepDistance; - - if (distanceTraveled >= range) { - remove(); - return; - } - } - } - - private void render() { - if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { - ParticleEffect.SOUL_FIRE_FLAME.display(location, 1, 0.0, 0.0, 0.0, 0.03); - } else { - ParticleEffect.FLAME.display(location, 1, 0.0, 0.0, 0.0, 0.03); - } - ParticleEffect.SMOKE_LARGE.display(location, 1, 0.0, 0.0, 0.0F, 0.06); - ParticleEffect.FIREWORKS_SPARK.display(location, 1, 0.0, 0.0, 0.0F, 0.06); - - location.getWorld().playSound(location, Sound.ENTITY_FIREWORK_ROCKET_BLAST, 1.0F, 0.01F); - - JCMethods.emitLight(location); - } - } - - @Override - public void handleCollision(final Collision collision) { - super.handleCollision(collision); - - if (collision.isRemovingFirst()) { - state = new CombustState(collision.getLocationFirst()); - } - } - - // This state is used for doing the explosion. - // ChargeState can transition to this state if the player takes damage while charging. - // TravelState can transition to this state if the projectile collides with terrain, entity, or collidable ability. - private class CombustState implements State { - private final long startTime; - private final long regenTime; - private boolean waitForRegen; - - public CombustState(Location location) { - this(location, false); - } - - public CombustState(Location location, boolean misfire) { - removalPolicy.removePolicyType(SwappedSlotsRemovalPolicy.class); - // This stops players from moving into a protected area to bypass the regen wait time. - removalPolicy.removePolicyType(CannotBendRemovalPolicy.class); - - ConfigurationSection config = JedCoreConfig.getConfig(player); - - this.startTime = System.currentTimeMillis(); - this.regenTime = config.getLong("Abilities.Fire.Combustion.RegenTime"); - this.waitForRegen = config.getBoolean("Abilities.Fire.Combustion.WaitForRegen"); - - double damage = config.getDouble("Abilities.Fire.Combustion.Damage"); - int fireTick = config.getInt("Abilities.Fire.Combustion.FireTick"); - int power = config.getInt("Abilities.Fire.Combustion.Power"); - boolean damageBlocks = config.getBoolean("Abilities.Fire.Combustion.DamageBlocks"); - boolean regenBlocks = config.getBoolean("Abilities.Fire.Combustion.RegenBlocks"); - - ExplosionMethod explosionMethod; - if (regenBlocks) { - explosionMethod = new RegenExplosionMethod(damageBlocks, regenTime); - } else { - explosionMethod = new PermanentExplosionMethod(damageBlocks); - } - - // Don't wait for regen if the blocks aren't even being destroyed. - if (!damageBlocks) { - waitForRegen = false; - } - - double modifier = 0; - if (misfire) { - modifier = config.getInt("Abilities.Fire.Combustion.MisfireModifier"); - } - - int destroyedCount = explosionMethod.explode(location, power + modifier, damage + modifier, fireTick); - - // Don't wait for regen if nothing was actually destroyed. - if (destroyedCount <= 0) { - waitForRegen = false; - } - - AirAbility.removeAirSpouts(location, power, player); - WaterAbility.removeWaterSpouts(location, power, player); - } - - @Override - public void update() { - if (!waitForRegen || System.currentTimeMillis() >= (this.startTime + this.regenTime)) { - remove(); - } - } - } - - private interface ExplosionMethod { - // Returns how many blocks were destroyed. - int explode(Location location, double size, double damage, int fireTick); - } - - private abstract class AbstractExplosionMethod implements ExplosionMethod { - protected List blocks = Arrays.asList( - Material.AIR, Material.VOID_AIR, Material.CAVE_AIR, Material.BEDROCK, Material.CHEST, Material.TRAPPED_CHEST, Material.OBSIDIAN, - Material.NETHER_PORTAL, Material.END_PORTAL, Material.END_PORTAL_FRAME, Material.FIRE, - Material.WATER, Material.LAVA, Material.DROPPER, Material.FURNACE, - Material.DISPENSER, Material.HOPPER, Material.BEACON, Material.BARRIER, Material.SPAWNER - ); - - private final boolean destroy; - private final Random rand = new Random(); - - public AbstractExplosionMethod(boolean destroy) { - this.destroy = destroy; - } - - public int explode(Location location, double size, double damage, int fireTick) { - render(location); - - if (!destroy) { - return 0; - } - - location.getWorld().createExplosion(location, 0.0F); - int destroyCount = destroyBlocks(location, (int)size); - damageEntities(location, size, damage, fireTick); - - return destroyCount; - } - - private void render(Location location) { - if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { - ParticleEffect.SOUL_FIRE_FLAME.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); - } else { - ParticleEffect.FLAME.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); - } - ParticleEffect.SMOKE_LARGE.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); - ParticleEffect.FIREWORKS_SPARK.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); - ParticleEffect.SMOKE_LARGE.display(location, 20, Math.random(), Math.random(), Math.random()); - ParticleEffect.EXPLOSION_HUGE.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); - - location.getWorld().playSound(location, Sound.ENTITY_GENERIC_EXPLODE, 1f, 1f); - } - - private int destroyBlocks(Location location, int size) { - int count = 0; - - for (Location l : GeneralMethods.getCircle(location, size, size, false, true, 0)) { - if (!RegionProtection.isRegionProtected(Combustion.this, l)) { - if (destroyBlock(l)) { - ++count; - } - } - } - - return count; - } - - private void damageEntities(Location location, double size, double damage, int fireTick) { - for (Entity e : GeneralMethods.getEntitiesAroundPoint(location, size)) { - if (e instanceof LivingEntity) { - if (!RegionProtection.isRegionProtected(Combustion.this, e.getLocation())) { - DamageHandler.damageEntity(e, damage, Combustion.this); - FireTick.set(e, fireTick); - } - } - } - } - - protected void placeRandomFire(Location location) { - int chance = rand.nextInt(3); - - if ((!(location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()).getType().isSolid())) || (chance != 0)) - return; - - location.getBlock().setType(Material.FIRE); - } - - protected void placeRandomBlock(Location location) { - int chance = rand.nextInt(3); - - if (!(location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()).getType().isSolid())) - return; - - Material block = location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()).getType(); - - if (chance == 0) - location.getBlock().setType(block); - } - - // Returns how many blocks were destroyed. - public abstract boolean destroyBlock(Location location); - } - - private class RegenExplosionMethod extends AbstractExplosionMethod { - private final long regenTime; - - public RegenExplosionMethod(boolean destroy, long regenTime) { - super(destroy); - this.regenTime = regenTime; - } - - @Override - public boolean destroyBlock(Location l) { - Block block = l.getBlock(); - - if (TempBlock.isTempBlock(block)) - TempBlock.revertBlock(block, Material.AIR); - if (TempBlock.isTempBlock(block)) - TempBlock.removeBlock(block); - - if (!MaterialUtil.isTransparent(block) && !blocks.contains(block.getType()) && !MaterialUtil.isSign(block)) { - new RegenTempBlock(block, Material.AIR, Material.AIR.createBlockData(), regenTime, false); - placeRandomBlock(l); - placeRandomFire(l); - - return true; - } - - return false; - } - } - - private class PermanentExplosionMethod extends AbstractExplosionMethod { - public PermanentExplosionMethod(boolean destroy) { - super(destroy); - } - - @Override - public boolean destroyBlock(Location l) { - Block block = l.getBlock(); - - if (!MaterialUtil.isTransparent(block) && !blocks.contains(block.getType()) && !MaterialUtil.isSign(block)) { - Block newBlock = l.getWorld().getBlockAt(l); - newBlock.setType(Material.AIR); - placeRandomBlock(l); - placeRandomFire(l); - - return true; - } - - return false; - } - } + private class TravelState implements State { + private Vector direction; + private final int range; + private final double speed; + private final boolean explodeOnDeath; + private final double entityCollisionRadius; + private double distanceTraveled; + + public TravelState() { + removalPolicy.removePolicyType(SwappedSlotsRemovalPolicy.class); + + Location origin = player.getEyeLocation().clone(); + origin.setY(origin.getY() - 0.8D); + location = origin.clone(); + + ConfigurationSection config = JedCoreConfig.getConfig(player); + + range = config.getInt("Abilities.Fire.Combustion.Range"); + speed = config.getDouble("Abilities.Fire.Combustion.Speed"); + explodeOnDeath = config.getBoolean("Abilities.Fire.Combustion.ExplodeOnDeath"); + entityCollisionRadius = config.getDouble("Abilities.Fire.Combustion.EntityCollisionRadius"); + + if (explodeOnDeath) { + removalPolicy.removePolicyType(CannotBendRemovalPolicy.class); + removalPolicy.removePolicyType(IsDeadRemovalPolicy.class); + } + + direction = player.getEyeLocation().getDirection().normalize(); + distanceTraveled = 0; + } + + @Override + public void update() { + if (explodeOnDeath && player.isDead()) { + state = new CombustState(location); + return; + } + + // Manually handle the region protection check because the CannotBendRemovalPolicy no longer checks it + // when explodeOnDeath is true. This stops players from firing Combustion and then walking into a + // protected area. + if (explodeOnDeath) { + if (RegionProtection.isRegionProtected(Combustion.this, player.getLocation())) { + remove(); + return; + } + } + + if (distanceTraveled >= range) { + remove(); + return; + } + + travel(); + } + + private void travel() { + double stepDistance = speed; + + for (int i = 0; i < (int) (speed * 5); ++i) { + render(); + + Sphere collider = new Sphere(location.toVector(), entityCollisionRadius); + + boolean hit = CollisionDetector.checkEntityCollisions(player, collider, (entity) -> { + location = entity.getLocation(); + state = new CombustState(location); + return true; + }); + + if (hit) { + return; + } + + if (!MaterialUtil.isTransparent(location.getBlock()) || isWater(location.getBlock())) { + Material blockMaterial = location.getBlock().getType(); + String blockMaterialName = blockMaterial.name().toLowerCase(); + + boolean shouldSkip = skipMaterials.contains(blockMaterialName); + + if (!shouldSkip) { + state = new CombustState(location); + return; + } + } + + direction = player.getEyeLocation().getDirection().normalize(); + location = location.add(direction.clone().multiply(stepDistance)); + + distanceTraveled += stepDistance; + + if (distanceTraveled >= range) { + remove(); + return; + } + } + } + + private void render() { + if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { + ParticleEffect.SOUL_FIRE_FLAME.display(location, 1, 0.0, 0.0, 0.0, 0.03); + } else { + ParticleEffect.FLAME.display(location, 1, 0.0, 0.0, 0.0, 0.03); + } + ParticleEffect.SMOKE_LARGE.display(location, 1, 0.0, 0.0, 0.0F, 0.06); + ParticleEffect.FIREWORKS_SPARK.display(location, 1, 0.0, 0.0, 0.0F, 0.06); + + location.getWorld().playSound(location, Sound.ENTITY_FIREWORK_ROCKET_BLAST, 1.0F, 0.01F); + + JCMethods.emitLight(location); + } + } + + @Override + public void handleCollision(final Collision collision) { + super.handleCollision(collision); + + if (collision.isRemovingFirst()) { + state = new CombustState(collision.getLocationFirst()); + } + } + + // This state is used for doing the explosion. + // ChargeState can transition to this state if the player takes damage while charging. + // TravelState can transition to this state if the projectile collides with terrain, entity, or collidable ability. + private class CombustState implements State { + private final long startTime; + private final long regenTime; + private boolean waitForRegen; + + public CombustState(Location location) { + this(location, false); + } + + public CombustState(Location location, boolean misfire) { + removalPolicy.removePolicyType(SwappedSlotsRemovalPolicy.class); + // This stops players from moving into a protected area to bypass the regen wait time. + removalPolicy.removePolicyType(CannotBendRemovalPolicy.class); + + ConfigurationSection config = JedCoreConfig.getConfig(player); + + this.startTime = System.currentTimeMillis(); + this.regenTime = config.getLong("Abilities.Fire.Combustion.RegenTime"); + this.waitForRegen = config.getBoolean("Abilities.Fire.Combustion.WaitForRegen"); + + double damage = config.getDouble("Abilities.Fire.Combustion.Damage"); + int fireTick = config.getInt("Abilities.Fire.Combustion.FireTick"); + int power = config.getInt("Abilities.Fire.Combustion.Power"); + boolean damageBlocks = config.getBoolean("Abilities.Fire.Combustion.DamageBlocks"); + boolean regenBlocks = config.getBoolean("Abilities.Fire.Combustion.RegenBlocks"); + + ExplosionMethod explosionMethod; + if (regenBlocks) { + explosionMethod = new RegenExplosionMethod(damageBlocks, regenTime); + } else { + explosionMethod = new PermanentExplosionMethod(damageBlocks); + } + + // Don't wait for regen if the blocks aren't even being destroyed. + if (!damageBlocks) { + waitForRegen = false; + } + + double modifier = 0; + if (misfire) { + modifier = config.getInt("Abilities.Fire.Combustion.MisfireModifier"); + } + + int destroyedCount = explosionMethod.explode(location, power + modifier, damage + modifier, fireTick); + + // Don't wait for regen if nothing was actually destroyed. + if (destroyedCount <= 0) { + waitForRegen = false; + } + + AirAbility.removeAirSpouts(location, power, player); + WaterAbility.removeWaterSpouts(location, power, player); + } + + @Override + public void update() { + if (!waitForRegen || System.currentTimeMillis() >= (this.startTime + this.regenTime)) { + remove(); + } + } + } + + private interface ExplosionMethod { + // Returns how many blocks were destroyed. + int explode(Location location, double size, double damage, int fireTick); + } + + private abstract class AbstractExplosionMethod implements ExplosionMethod { + protected List blocks = Arrays.asList( + Material.AIR, Material.VOID_AIR, Material.CAVE_AIR, Material.BEDROCK, Material.CHEST, Material.TRAPPED_CHEST, Material.OBSIDIAN, + Material.NETHER_PORTAL, Material.END_PORTAL, Material.END_PORTAL_FRAME, Material.FIRE, + Material.WATER, Material.LAVA, Material.DROPPER, Material.FURNACE, + Material.DISPENSER, Material.HOPPER, Material.BEACON, Material.BARRIER, Material.SPAWNER + ); + + private final boolean destroy; + private final Random rand = new Random(); + + public AbstractExplosionMethod(boolean destroy) { + this.destroy = destroy; + } + + public int explode(Location location, double size, double damage, int fireTick) { + render(location); + + if (!destroy) { + return 0; + } + + location.getWorld().createExplosion(location, 0.0F); + int destroyCount = destroyBlocks(location, (int)size); + damageEntities(location, size, damage, fireTick); + + return destroyCount; + } + + private void render(Location location) { + if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { + ParticleEffect.SOUL_FIRE_FLAME.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); + } else { + ParticleEffect.FLAME.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); + } + ParticleEffect.SMOKE_LARGE.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); + ParticleEffect.FIREWORKS_SPARK.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); + ParticleEffect.SMOKE_LARGE.display(location, 20, Math.random(), Math.random(), Math.random()); + ParticleEffect.EXPLOSION_HUGE.display(location, 20, Math.random(), Math.random(), Math.random(), 0.5); + + location.getWorld().playSound(location, Sound.ENTITY_GENERIC_EXPLODE, 1f, 1f); + } + + private int destroyBlocks(Location location, int size) { + int count = 0; + + for (Location l : GeneralMethods.getCircle(location, size, size, false, true, 0)) { + if (!RegionProtection.isRegionProtected(Combustion.this, l)) { + if (destroyBlock(l)) { + ++count; + } + } + } + + return count; + } + + private void damageEntities(Location location, double size, double damage, int fireTick) { + for (Entity e : GeneralMethods.getEntitiesAroundPoint(location, size)) { + if (e instanceof LivingEntity) { + if (!RegionProtection.isRegionProtected(Combustion.this, e.getLocation())) { + DamageHandler.damageEntity(e, damage, Combustion.this); + FireTick.set(e, fireTick); + } + } + } + } + + protected void placeRandomFire(Location location) { + int chance = rand.nextInt(3); + + if ((!(location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()).getType().isSolid())) || (chance != 0)) + return; + + location.getBlock().setType(Material.FIRE); + } + + protected void placeRandomBlock(Location location) { + int chance = rand.nextInt(3); + + if (!(location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()).getType().isSolid())) + return; + + Material block = location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()).getType(); + + if (chance == 0) + location.getBlock().setType(block); + } + + // Returns how many blocks were destroyed. + public abstract boolean destroyBlock(Location location); + } + + private class RegenExplosionMethod extends AbstractExplosionMethod { + private final long regenTime; + + public RegenExplosionMethod(boolean destroy, long regenTime) { + super(destroy); + this.regenTime = regenTime; + } + + @Override + public boolean destroyBlock(Location l) { + Block block = l.getBlock(); + + if (TempBlock.isTempBlock(block)) + TempBlock.revertBlock(block, Material.AIR); + if (TempBlock.isTempBlock(block)) + TempBlock.removeBlock(block); + + if (!MaterialUtil.isTransparent(block) && !blocks.contains(block.getType()) && !MaterialUtil.isSign(block)) { + new RegenTempBlock(block, Material.AIR, Material.AIR.createBlockData(), regenTime, false); + placeRandomBlock(l); + placeRandomFire(l); + + return true; + } + + return false; + } + } + + private class PermanentExplosionMethod extends AbstractExplosionMethod { + public PermanentExplosionMethod(boolean destroy) { + super(destroy); + } + + @Override + public boolean destroyBlock(Location l) { + Block block = l.getBlock(); + + if (!MaterialUtil.isTransparent(block) && !blocks.contains(block.getType()) && !MaterialUtil.isSign(block)) { + Block newBlock = l.getWorld().getBlockAt(l); + newBlock.setType(Material.AIR); + placeRandomBlock(l); + placeRandomFire(l); + + return true; + } + + return false; + } + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/firebending/Discharge.java b/src/com/jedk1/jedcore/ability/firebending/Discharge.java index 705eeb2..1f27388 100644 --- a/src/com/jedk1/jedcore/ability/firebending/Discharge.java +++ b/src/com/jedk1/jedcore/ability/firebending/Discharge.java @@ -12,7 +12,6 @@ import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.configuration.ConfigurationSection; @@ -44,6 +43,9 @@ public class Discharge extends LightningAbility implements AddonAbility { @Attribute("CollisionRadius") private double entityCollisionRadius; + private float soundVolume; + private int soundInterval; + public Discharge(Player player) { super(player); @@ -74,6 +76,9 @@ public void setFields() { duration = config.getLong("Abilities.Fire.Discharge.Duration"); slotSwapping = config.getBoolean("Abilities.Fire.Discharge.SlotSwapping"); entityCollisionRadius = config.getDouble("Abilities.Fire.Discharge.EntityCollisionRadius"); + + soundVolume = (float) config.getDouble("Abilities.Fire.Discharge.Sound.Volume"); + soundInterval = config.getInt("Abilities.Fire.Discharge.Sound.Interval"); branchSpace = 0.2; } @@ -138,8 +143,8 @@ private void advanceLocation() { playLightningbendingParticle(l.clone(), 0f, 0f, 0f); JCMethods.emitLight(l.clone()); - if (rand.nextInt(3) == 0) { - player.getWorld().playSound(l, Sound.ENTITY_CREEPER_PRIMED, 1, 0); + if (rand.nextInt(soundInterval) == 0) { + player.getWorld().playSound(l, Sound.ENTITY_BEE_HURT, soundVolume, 0.2f); } Vector vec = l.toVector(); @@ -158,8 +163,8 @@ private void advanceLocation() { JCMethods.emitLight(entity.getLocation()); } - entity.getWorld().playSound(entity.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 1, 0); - player.getWorld().playSound(player.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 1, 0); + entity.getWorld().playSound(entity.getLocation(), Sound.ENTITY_BEE_HURT, soundVolume, 0.2f); + player.getWorld().playSound(player.getLocation(), Sound.ENTITY_BEE_HURT, soundVolume, 0.2f); return true; }); diff --git a/src/com/jedk1/jedcore/ability/firebending/FireBall.java b/src/com/jedk1/jedcore/ability/firebending/FireBall.java index 7d739f0..2631565 100644 --- a/src/com/jedk1/jedcore/ability/firebending/FireBall.java +++ b/src/com/jedk1/jedcore/ability/firebending/FireBall.java @@ -1,16 +1,26 @@ package com.jedk1.jedcore.ability.firebending; import com.jedk1.jedcore.JCMethods; +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.collision.CollisionDetector; import com.jedk1.jedcore.collision.Sphere; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.util.AirShieldReflector; import com.jedk1.jedcore.util.FireTick; +import com.projectkorra.projectkorra.Element.SubElement; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.BlueFireAbility; import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.ability.FireAbility; import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.airbending.AirShield; import com.projectkorra.projectkorra.attribute.Attribute; +import com.projectkorra.projectkorra.firebending.BlazeArc; +import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.region.RegionProtection; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Entity; @@ -18,17 +28,6 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.Element.SubElement; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.BlueFireAbility; -import com.projectkorra.projectkorra.ability.FireAbility; -import com.projectkorra.projectkorra.firebending.BlazeArc; -import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; - public class FireBall extends FireAbility implements AddonAbility { private Location location; diff --git a/src/com/jedk1/jedcore/ability/firebending/FireBreath.java b/src/com/jedk1/jedcore/ability/firebending/FireBreath.java index 3e3e2c5..f6fdd7c 100644 --- a/src/com/jedk1/jedcore/ability/firebending/FireBreath.java +++ b/src/com/jedk1/jedcore/ability/firebending/FireBreath.java @@ -1,18 +1,24 @@ package com.jedk1.jedcore.ability.firebending; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.UUID; - import com.jedk1.jedcore.JCMethods; +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.listener.CommandListener; import com.jedk1.jedcore.util.FireTick; +import com.projectkorra.projectkorra.Element; +import com.projectkorra.projectkorra.Element.SubElement; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.BlueFireAbility; +import com.projectkorra.projectkorra.ability.FireAbility; import com.projectkorra.projectkorra.attribute.Attribute; +import com.projectkorra.projectkorra.firebending.BlazeArc; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.ChatUtil; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.TempBlock; +import com.projectkorra.projectkorra.waterbending.ice.PhaseChange; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Particle; @@ -23,405 +29,394 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.Element; -import com.projectkorra.projectkorra.Element.SubElement; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.BlueFireAbility; -import com.projectkorra.projectkorra.ability.FireAbility; -import com.projectkorra.projectkorra.firebending.BlazeArc; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; -import com.projectkorra.projectkorra.util.TempBlock; -import com.projectkorra.projectkorra.waterbending.ice.PhaseChange; +import java.util.*; public class FireBreath extends FireAbility implements AddonAbility { - public static List rainbowPlayer = new ArrayList<>(); - - private int ticks; - Random rand = new Random(); - private final List locations = new ArrayList<>(); - - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.DURATION) - private long duration; - private int particles; - @Attribute(Attribute.DAMAGE) - private double playerDamage; - @Attribute(Attribute.DAMAGE) - private double mobDamage; - @Attribute(Attribute.DURATION) - private int fireDuration; - @Attribute(Attribute.RANGE) - private int range; - private boolean spawnFire; - private boolean meltEnabled; - private int meltChance; - - - public FireBreath(Player player) { - super(player); - if (!bPlayer.canBend(this) || hasAbility(player, FireBreath.class)) { - return; - } - - setFields(); - - if (bPlayer.isAvatarState()) { - range = range * 2; - playerDamage = playerDamage * 1.5; - mobDamage = mobDamage * 2; - duration = duration * 3; - } else if (JCMethods.isSozinsComet(player.getWorld())) { - range = range * 2; - playerDamage = playerDamage * 1.5; - mobDamage = mobDamage * 2; - } - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Fire.FireBreath.Cooldown"); - duration = config.getLong("Abilities.Fire.FireBreath.Duration"); - particles = config.getInt("Abilities.Fire.FireBreath.Particles"); - playerDamage = config.getDouble("Abilities.Fire.FireBreath.Damage.Player"); - mobDamage = config.getDouble("Abilities.Fire.FireBreath.Damage.Mob"); - fireDuration = config.getInt("Abilities.Fire.FireBreath.FireDuration"); - range = config.getInt("Abilities.Fire.FireBreath.Range"); - spawnFire = config.getBoolean("Abilities.Fire.FireBreath.Avatar.FireEnabled"); - meltEnabled = config.getBoolean("Abilities.Fire.FireBreath.Melt.Enabled"); - meltChance = config.getInt("Abilities.Fire.FireBreath.Melt.Chance"); - - applyModifiers(); - } - - private void applyModifiers() { - if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { - cooldown *= BlueFireAbility.getCooldownFactor(); - range *= BlueFireAbility.getRangeFactor(); - playerDamage *= BlueFireAbility.getDamageFactor(); - mobDamage *= BlueFireAbility.getDamageFactor(); - } - - if (isDay(player.getWorld())) { - cooldown -= ((long) getDayFactor(cooldown) - cooldown); - range = (int) getDayFactor(range); - playerDamage = getDayFactor(playerDamage); - mobDamage = getDayFactor(mobDamage); - } - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - if (!bPlayer.canBendIgnoreCooldowns(this)) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (!player.isSneaking()) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (System.currentTimeMillis() < getStartTime() + duration) { - createBeam(); - } else { - bPlayer.addCooldown(this); - remove(); - } - } - - private boolean isLocationSafe(Location loc) { - Block block = loc.getBlock(); - if (RegionProtection.isRegionProtected(player, loc, this)) { - return false; - } - if (!isTransparent(block)) { - return false; - } - return !isWater(block); - } - - private void createBeam() { - Location loc = player.getEyeLocation(); - Vector dir = player.getLocation().getDirection(); - double step = 1; - double size = 0; - double offset = 0; - double damageRegion = 1.5; - - locations.clear(); - - for (double k = 0; k < range; k += step) { - loc = loc.add(dir.clone().multiply(step)); - size += 0.005; - offset += 0.3; - damageRegion += 0.01; - if (meltEnabled) { - for (Block b : GeneralMethods.getBlocksAroundPoint(loc, damageRegion)) { - if (isIce(b) && rand.nextInt(meltChance) == 0) { - if (TempBlock.isTempBlock(b)) { - TempBlock temp = TempBlock.get(b); - if (PhaseChange.getFrozenBlocksMap().containsKey(temp)) { - temp.revertBlock(); - PhaseChange.getFrozenBlocksMap().remove(temp); - } - } - } - } - } - if (!isLocationSafe(loc)) - return; - - locations.add(loc); - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(loc, damageRegion)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) { - if (entity instanceof Player) { - FireTick.set(entity, fireDuration / 50); - DamageHandler.damageEntity(entity, playerDamage, this); - } else { - FireTick.set(entity, fireDuration / 50); - DamageHandler.damageEntity(entity, mobDamage, this); - } - } - } - - playFirebendingSound(loc); - if (bPlayer.isAvatarState() && spawnFire) { - new BlazeArc(player, loc, dir, 2); - } - - if (rainbowPlayer.contains(player.getUniqueId())) { - ticks++; - if (ticks >= 301) - ticks = 0; - if (isInRange(ticks, 0, 50)) { - for (int i = 0; i < 6; i++) - displayParticle(getOffsetLocation(loc, offset), 1, 140, 32, 32); - } else if (isInRange(ticks, 51, 100)) { - for (int i = 0; i < 6; i++) - displayParticle(getOffsetLocation(loc, offset), 1, 196, 93, 0); - } else if (isInRange(ticks, 101, 150)) { - for (int i = 0; i < 6; i++) - displayParticle(getOffsetLocation(loc, offset), 1, 186, 166, 37); - } else if (isInRange(ticks, 151, 200)) { - for (int i = 0; i < 6; i++) - displayParticle(getOffsetLocation(loc, offset), 1, 36, 171, 47); - } else if (isInRange(ticks, 201, 250)) { - for (int i = 0; i < 6; i++) - displayParticle(getOffsetLocation(loc, offset), 1, 36, 142, 171); - } else if (isInRange(ticks, 251, 300)) { - for (int i = 0; i < 6; i++) - displayParticle(getOffsetLocation(loc, offset), 1, 128, 36, 171); - } - } else { - playFirebendingParticles(loc, particles, Math.random(), Math.random(), Math.random()); - ParticleEffect.SMOKE_NORMAL.display(loc, particles, Math.random(), Math.random(), Math.random(), size); - JCMethods.emitLight(loc); - } - } - } - - private void displayParticle(Location location, int amount, int r, int g, int b) { - ParticleEffect.REDSTONE.display(location, amount, 0, 0, 0, 0.005, new Particle.DustOptions(Color.fromRGB(r, g, b), 1)); - JCMethods.emitLight(location); - } - - private boolean isInRange(int x, int min, int max) { - return min <= x && x <= max; - } - - /** - * Generates an offset location around a given location with variable offset - * amount. - */ - private Location getOffsetLocation(Location loc, double offset) { - return loc.clone().add((float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset)); - } - - public static void toggleRainbowBreath(Player player, boolean activate) { - ConfigurationSection config = JedCoreConfig.getConfig(player); - - boolean easterEgg = config.getBoolean("Abilities.Fire.FireBreath.RainbowBreath.Enabled"); - String bindMsg = ChatUtil.color(config.getString("Abilities.Fire.FireBreath.RainbowBreath.EnabledMessage", "")); - String unbindMsg = ChatUtil.color(config.getString("Abilities.Fire.FireBreath.RainbowBreath.DisabledMessage", "")); - String deniedMsg = ChatUtil.color(config.getString("Abilities.Fire.FireBreath.RainbowBreath.NoAccess", "")); - - if (easterEgg && (player.hasPermission("bending.ability.FireBreath.RainbowBreath") - || Arrays.asList(CommandListener.developers).contains(player.getUniqueId().toString()))) { - if (activate) { - if (!rainbowPlayer.contains(player.getUniqueId())) { - rainbowPlayer.add(player.getUniqueId()); - if (!bindMsg.equals("")) player.sendMessage(Element.FIRE.getColor() + bindMsg); - } - } else { - if (rainbowPlayer.contains(player.getUniqueId())) { - rainbowPlayer.remove(player.getUniqueId()); - if (!unbindMsg.equals("")) player.sendMessage(Element.FIRE.getColor() + unbindMsg); - } - } - } else if (!deniedMsg.equals("")) { - player.sendMessage(Element.FIRE.getColor() + deniedMsg); - } - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return player.getLocation(); - } - - @Override - public List getLocations() { - return locations; - } - - @Override - public String getName() { - return "FireBreath"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Fire.FireBreath.Description"); - } - - public static List getRainbowPlayer() { - return rainbowPlayer; - } - - public static void setRainbowPlayer(List rainbowPlayer) { - FireBreath.rainbowPlayer = rainbowPlayer; - } - - public int getTicks() { - return ticks; - } - - public void setTicks(int ticks) { - this.ticks = ticks; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - public int getParticles() { - return particles; - } - - public void setParticles(int particles) { - this.particles = particles; - } - - public double getPlayerDamage() { - return playerDamage; - } - - public void setPlayerDamage(double playerDamage) { - this.playerDamage = playerDamage; - } - - public double getMobDamage() { - return mobDamage; - } - - public void setMobDamage(double mobDamage) { - this.mobDamage = mobDamage; - } - - public int getFireDuration() { - return fireDuration; - } - - public void setFireDuration(int fireDuration) { - this.fireDuration = fireDuration; - } - - public int getRange() { - return range; - } - - public void setRange(int range) { - this.range = range; - } - - public boolean isSpawnFire() { - return spawnFire; - } - - public void setSpawnFire(boolean spawnFire) { - this.spawnFire = spawnFire; - } - - public boolean isMeltEnabled() { - return meltEnabled; - } - - public void setMeltEnabled(boolean meltEnabled) { - this.meltEnabled = meltEnabled; - } - - public int getMeltChance() { - return meltChance; - } - - public void setMeltChance(int meltChance) { - this.meltChance = meltChance; - } - - @Override - public void load() {} - - @Override - public void stop() {} + public static List rainbowPlayer = new ArrayList<>(); + + private int ticks; + Random rand = new Random(); + private final List locations = new ArrayList<>(); + + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.DURATION) + private long duration; + private int particles; + @Attribute("Player" + Attribute.DAMAGE) + private double playerDamage; + @Attribute("Mob" + Attribute.DAMAGE) + private double mobDamage; + @Attribute(Attribute.DURATION) + private int fireDuration; + @Attribute(Attribute.RANGE) + private int range; + private boolean spawnFire; + private boolean meltEnabled; + private int meltChance; + + + public FireBreath(Player player) { + super(player); + if (!bPlayer.canBend(this) || hasAbility(player, FireBreath.class)) { + return; + } + + setFields(); + + if (bPlayer.isAvatarState()) { + range = range * 2; + playerDamage = playerDamage * 1.5; + mobDamage = mobDamage * 2; + duration = duration * 3; + } else if (JCMethods.isSozinsComet(player.getWorld())) { + range = range * 2; + playerDamage = playerDamage * 1.5; + mobDamage = mobDamage * 2; + } + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Fire.FireBreath.Cooldown"); + duration = config.getLong("Abilities.Fire.FireBreath.Duration"); + particles = config.getInt("Abilities.Fire.FireBreath.Particles"); + playerDamage = config.getDouble("Abilities.Fire.FireBreath.Damage.Player"); + mobDamage = config.getDouble("Abilities.Fire.FireBreath.Damage.Mob"); + fireDuration = config.getInt("Abilities.Fire.FireBreath.FireDuration"); + range = config.getInt("Abilities.Fire.FireBreath.Range"); + spawnFire = config.getBoolean("Abilities.Fire.FireBreath.Avatar.FireEnabled"); + meltEnabled = config.getBoolean("Abilities.Fire.FireBreath.Melt.Enabled"); + meltChance = config.getInt("Abilities.Fire.FireBreath.Melt.Chance"); + + applyModifiers(); + } + + private void applyModifiers() { + if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { + cooldown *= BlueFireAbility.getCooldownFactor(); + range *= BlueFireAbility.getRangeFactor(); + playerDamage *= BlueFireAbility.getDamageFactor(); + mobDamage *= BlueFireAbility.getDamageFactor(); + } + + if (isDay(player.getWorld())) { + cooldown -= ((long) getDayFactor(cooldown) - cooldown); + range = (int) getDayFactor(range); + playerDamage = getDayFactor(playerDamage); + mobDamage = getDayFactor(mobDamage); + } + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + if (!bPlayer.canBendIgnoreCooldowns(this)) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (!player.isSneaking()) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (System.currentTimeMillis() < getStartTime() + duration) { + createBeam(); + } else { + bPlayer.addCooldown(this); + remove(); + } + } + + private boolean isLocationSafe(Location loc) { + Block block = loc.getBlock(); + if (RegionProtection.isRegionProtected(player, loc, this)) { + return false; + } + if (!isTransparent(block)) { + return false; + } + return !isWater(block); + } + + private void createBeam() { + Location loc = player.getEyeLocation(); + Vector dir = player.getLocation().getDirection(); + double step = 1; + double size = 0; + double offset = 0; + double damageRegion = 1.5; + + locations.clear(); + + for (double k = 0; k < range; k += step) { + loc = loc.add(dir.clone().multiply(step)); + size += 0.005; + offset += 0.3; + damageRegion += 0.01; + if (meltEnabled) { + for (Block b : GeneralMethods.getBlocksAroundPoint(loc, damageRegion)) { + if (isIce(b) && rand.nextInt(meltChance) == 0) { + if (TempBlock.isTempBlock(b)) { + TempBlock temp = TempBlock.get(b); + if (PhaseChange.getFrozenBlocksMap().containsKey(temp)) { + temp.revertBlock(); + PhaseChange.getFrozenBlocksMap().remove(temp); + } + } + } + } + } + if (!isLocationSafe(loc)) + return; + + locations.add(loc); + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(loc, damageRegion)) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) { + if (entity instanceof Player) { + FireTick.set(entity, fireDuration / 50); + DamageHandler.damageEntity(entity, playerDamage, this); + } else { + FireTick.set(entity, fireDuration / 50); + DamageHandler.damageEntity(entity, mobDamage, this); + } + } + } + + playFirebendingSound(loc); + if (bPlayer.isAvatarState() && spawnFire) { + new BlazeArc(player, loc, dir, 2); + } + + if (rainbowPlayer.contains(player.getUniqueId())) { + ticks++; + if (ticks >= 301) + ticks = 0; + if (isInRange(ticks, 0, 50)) { + for (int i = 0; i < 6; i++) + displayParticle(getOffsetLocation(loc, offset), 1, 140, 32, 32); + } else if (isInRange(ticks, 51, 100)) { + for (int i = 0; i < 6; i++) + displayParticle(getOffsetLocation(loc, offset), 1, 196, 93, 0); + } else if (isInRange(ticks, 101, 150)) { + for (int i = 0; i < 6; i++) + displayParticle(getOffsetLocation(loc, offset), 1, 186, 166, 37); + } else if (isInRange(ticks, 151, 200)) { + for (int i = 0; i < 6; i++) + displayParticle(getOffsetLocation(loc, offset), 1, 36, 171, 47); + } else if (isInRange(ticks, 201, 250)) { + for (int i = 0; i < 6; i++) + displayParticle(getOffsetLocation(loc, offset), 1, 36, 142, 171); + } else if (isInRange(ticks, 251, 300)) { + for (int i = 0; i < 6; i++) + displayParticle(getOffsetLocation(loc, offset), 1, 128, 36, 171); + } + } else { + playFirebendingParticles(loc, particles, Math.random(), Math.random(), Math.random()); + ParticleEffect.SMOKE_NORMAL.display(loc, particles, Math.random(), Math.random(), Math.random(), size); + JCMethods.emitLight(loc); + } + } + } + + private void displayParticle(Location location, int amount, int r, int g, int b) { + ParticleEffect.REDSTONE.display(location, amount, 0, 0, 0, 0.005, new Particle.DustOptions(Color.fromRGB(r, g, b), 1)); + JCMethods.emitLight(location); + } + + private boolean isInRange(int x, int min, int max) { + return min <= x && x <= max; + } + + /** + * Generates an offset location around a given location with variable offset + * amount. + */ + private Location getOffsetLocation(Location loc, double offset) { + return loc.clone().add((float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset)); + } + + public static void toggleRainbowBreath(Player player, boolean activate) { + ConfigurationSection config = JedCoreConfig.getConfig(player); + + boolean easterEgg = config.getBoolean("Abilities.Fire.FireBreath.RainbowBreath.Enabled"); + String bindMsg = ChatUtil.color(config.getString("Abilities.Fire.FireBreath.RainbowBreath.EnabledMessage", "")); + String unbindMsg = ChatUtil.color(config.getString("Abilities.Fire.FireBreath.RainbowBreath.DisabledMessage", "")); + String deniedMsg = ChatUtil.color(config.getString("Abilities.Fire.FireBreath.RainbowBreath.NoAccess", "")); + + if (easterEgg && (player.hasPermission("bending.ability.FireBreath.RainbowBreath") + || Arrays.asList(CommandListener.developers).contains(player.getUniqueId().toString()))) { + if (activate) { + if (!rainbowPlayer.contains(player.getUniqueId())) { + rainbowPlayer.add(player.getUniqueId()); + if (!bindMsg.equals("")) player.sendMessage(Element.FIRE.getColor() + bindMsg); + } + } else { + if (rainbowPlayer.contains(player.getUniqueId())) { + rainbowPlayer.remove(player.getUniqueId()); + if (!unbindMsg.equals("")) player.sendMessage(Element.FIRE.getColor() + unbindMsg); + } + } + } else if (!deniedMsg.equals("")) { + player.sendMessage(Element.FIRE.getColor() + deniedMsg); + } + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return player.getLocation(); + } + + @Override + public List getLocations() { + return locations; + } + + @Override + public String getName() { + return "FireBreath"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Fire.FireBreath.Description"); + } + + public static List getRainbowPlayer() { + return rainbowPlayer; + } + + public static void setRainbowPlayer(List rainbowPlayer) { + FireBreath.rainbowPlayer = rainbowPlayer; + } + + public int getTicks() { + return ticks; + } + + public void setTicks(int ticks) { + this.ticks = ticks; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public int getParticles() { + return particles; + } + + public void setParticles(int particles) { + this.particles = particles; + } + + public double getPlayerDamage() { + return playerDamage; + } + + public void setPlayerDamage(double playerDamage) { + this.playerDamage = playerDamage; + } + + public double getMobDamage() { + return mobDamage; + } + + public void setMobDamage(double mobDamage) { + this.mobDamage = mobDamage; + } + + public int getFireDuration() { + return fireDuration; + } + + public void setFireDuration(int fireDuration) { + this.fireDuration = fireDuration; + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public boolean isSpawnFire() { + return spawnFire; + } + + public void setSpawnFire(boolean spawnFire) { + this.spawnFire = spawnFire; + } + + public boolean isMeltEnabled() { + return meltEnabled; + } + + public void setMeltEnabled(boolean meltEnabled) { + this.meltEnabled = meltEnabled; + } + + public int getMeltChance() { + return meltChance; + } + + public void setMeltChance(int meltChance) { + this.meltChance = meltChance; + } + + @Override + public void load() {} + + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Fire.FireBreath.Enabled"); - } -} + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Fire.FireBreath.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/firebending/FireComet.java b/src/com/jedk1/jedcore/ability/firebending/FireComet.java index d49f2d4..2cdd262 100644 --- a/src/com/jedk1/jedcore/ability/firebending/FireComet.java +++ b/src/com/jedk1/jedcore/ability/firebending/FireComet.java @@ -13,7 +13,6 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - import com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.Material; diff --git a/src/com/jedk1/jedcore/ability/firebending/FirePunch.java b/src/com/jedk1/jedcore/ability/firebending/FirePunch.java index 1d954b9..c80d53c 100644 --- a/src/com/jedk1/jedcore/ability/firebending/FirePunch.java +++ b/src/com/jedk1/jedcore/ability/firebending/FirePunch.java @@ -1,11 +1,6 @@ package com.jedk1.jedcore.ability.firebending; import com.jedk1.jedcore.JCMethods; -import org.bukkit.Location; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; - import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.util.FireTick; @@ -18,6 +13,11 @@ import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; +import org.bukkit.Location; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.MainHand; public class FirePunch extends FireAbility implements AddonAbility { @@ -28,6 +28,8 @@ public class FirePunch extends FireAbility implements AddonAbility { @Attribute(Attribute.FIRE_TICK) private int fireTicks; + private Boolean flameInMainHand = null; + private Location location; public FirePunch(Player player) { @@ -70,12 +72,26 @@ public void progress() { return; } - location = GeneralMethods.getRightSide(player.getLocation(), 0.55) - .add(0, 1.2, 0) - .add(player.getLocation().getDirection().multiply(0.8)); - playFirebendingParticles(location, 3, 0, 0, 0); - ParticleEffect.SMOKE_NORMAL.display(location, 1); - JCMethods.emitLight(location); + Location hand = getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.75D)).toLocation(player.getWorld()); + + playFirebendingParticles(hand, 3, 0, 0, 0); + ParticleEffect.SMOKE_NORMAL.display(hand, 1); + JCMethods.emitLight(hand); + } + + public static void swapHands(Player player) { + FirePunch fp = getAbility(player, FirePunch.class); + if (fp == null) + return; + if (fp.flameInMainHand == null) + fp.flameInMainHand = true; + else fp.flameInMainHand = !fp.flameInMainHand; + } + + public Location getRightHandPos() { + return (player.getMainHand() == MainHand.RIGHT == ((flameInMainHand == null) || flameInMainHand) ? + GeneralMethods.getRightSide(player.getLocation(), .55) : + GeneralMethods.getLeftSide(player.getLocation(), .55)).add(0, 1.2, 0); } public void punch(LivingEntity target) { diff --git a/src/com/jedk1/jedcore/ability/firebending/FireShots.java b/src/com/jedk1/jedcore/ability/firebending/FireShots.java index a03efeb..39f7332 100644 --- a/src/com/jedk1/jedcore/ability/firebending/FireShots.java +++ b/src/com/jedk1/jedcore/ability/firebending/FireShots.java @@ -1,416 +1,411 @@ package com.jedk1.jedcore.ability.firebending; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - import com.jedk1.jedcore.JCMethods; +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.collision.CollisionDetector; import com.jedk1.jedcore.collision.Sphere; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.jedk1.jedcore.util.AirShieldReflector; import com.jedk1.jedcore.util.FireTick; -import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.Element.SubElement; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.*; import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.airbending.AirShield; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; - -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.Element.SubElement; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.Ability; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.BlueFireAbility; -import com.projectkorra.projectkorra.ability.FireAbility; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; import org.bukkit.inventory.MainHand; import org.bukkit.util.Vector; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + public class FireShots extends FireAbility implements AddonAbility { - private final List shots = new ArrayList<>(); - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute("MaxShots") - private int startAmount; - @Attribute(Attribute.FIRE_TICK) - private int fireticks; - @Attribute(Attribute.RANGE) - private int range; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute("CollisionRadius") - private double collisionRadius; - private Boolean flameInMainHand = null; - - public int amount; - - public FireShots(Player player){ - super(player); - - if (!bPlayer.canBend(this) || hasAbility(player, FireShots.class)) { - return; - } - - if (!player.hasGravity()) - player.setGravity(true); - - setFields(); - - amount = startAmount; - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Fire.FireShots.Cooldown"); - startAmount = config.getInt("Abilities.Fire.FireShots.FireBalls"); - fireticks = config.getInt("Abilities.Fire.FireShots.FireDuration"); - range = config.getInt("Abilities.Fire.FireShots.Range"); - damage = config.getDouble("Abilities.Fire.FireShots.Damage"); - collisionRadius = config.getDouble("Abilities.Fire.FireShots.CollisionRadius"); - - applyModifiers(); - } - - private void applyModifiers() { - if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { - cooldown *= BlueFireAbility.getCooldownFactor(); - range *= BlueFireAbility.getRangeFactor(); - damage *= BlueFireAbility.getDamageFactor(); - } - - if (isDay(player.getWorld())) { - cooldown -= ((long) getDayFactor(cooldown) - cooldown); - range = (int) getDayFactor(range); - damage = getDayFactor(damage); - } - } - - public class FireShot { - - private final Ability ability; - private final Player player; - private Location location; - private final int range; - private final int fireTicks; - private double distanceTravelled; - private final double damage; - private Vector direction = null; - - public FireShot(Ability ability, Player player, Location location, int range, int fireTicks, double damage) { - this.ability = ability; - this.player = player; - this.location = location; - this.range = range; - this.fireTicks = fireTicks; - this.damage = damage; - } - - public boolean progress() { - if (player.isDead() || !player.isOnline()) { - return false; - } - if (distanceTravelled >= range) { - return false; - } - for (int i = 0; i < 2; i++) { - distanceTravelled ++; - if (distanceTravelled >= range) - return false; - - Vector dir = direction; - if (dir == null) { - dir = this.player.getLocation().getDirection().clone(); - } - - location = location.add(dir); - - if (GeneralMethods.isSolid(location.getBlock()) || isWater(location.getBlock())){ - return false; - } - - if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { - ParticleEffect.SOUL_FIRE_FLAME.display(location, 5, 0.0, 0.0, 0.0, 0.02); - } else { - ParticleEffect.FLAME.display(location, 5, 0.0, 0.0, 0.0, 0.02); - } - ParticleEffect.SMOKE_NORMAL.display(location, 2, 0.0, 0.0, 0.0, 0.01); - - JCMethods.emitLight(location); - - Sphere collider = new Sphere(location.toVector(), collisionRadius); - - boolean hit = CollisionDetector.checkEntityCollisions(player, collider, (entity) -> { - DamageHandler.damageEntity(entity, damage, ability); - FireTick.set(entity, Math.round(fireTicks / 50F)); - new FireDamageTimer(entity, player, FireShots.this); - return true; - }); - - if (hit) { - return false; - } - } - return true; - } - - public Ability getAbility() { - return ability; - } - - public Player getPlayer() { - return player; - } - - public Location getLocation() { - return location; - } - - public void setLocation(Location location) { - this.location = location; - } - - public int getRange() { - return range; - } - - public int getFireTicks() { - return fireTicks; - } - - public double getDistanceTravelled() { - return distanceTravelled; - } - - public void setDistanceTravelled(double distanceTravelled) { - this.distanceTravelled = distanceTravelled; - } - - public double getDamage() { - return damage; - } - - public Vector getDirection() { - return direction; - } - - public void setDirection(Vector direction) { - this.direction = direction; - } - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - - if (!bPlayer.canBendIgnoreCooldowns(this)) { - amount = 0; - if (!bPlayer.isOnCooldown(this)) { - bPlayer.addCooldown(this); - } - } - - shots.removeIf(shot -> !shot.progress()); - - if (amount <= 0 && shots.isEmpty()) { - remove(); - return; - } - - if (amount > 0) { - displayFireBalls(); - } - } - - public static void fireShot(Player player) { - FireShots fs = getAbility(player, FireShots.class); - if (fs != null) { - fs.fireShot(); - } - } - - public static void swapHands(Player player) { - FireShots fs = getAbility(player, FireShots.class); - if (fs == null) - return; - if (fs.flameInMainHand == null) - fs.flameInMainHand = true; - else fs.flameInMainHand = !fs.flameInMainHand; - } - - public void fireShot() { - if (amount >= 1) { - if (--amount <= 0) { - bPlayer.addCooldown(this); - } - shots.add(new FireShot(this, player, getRightHandPos(), range, fireticks, damage)); - } - } - - public Location getRightHandPos() { - return (player.getMainHand()==MainHand.RIGHT == ((flameInMainHand == null) || flameInMainHand) ? - GeneralMethods.getRightSide(player.getLocation(), .55) : - GeneralMethods.getLeftSide(player.getLocation(), .55)).add(0, 1.2, 0); - } - - private void displayFireBalls() { - playFirebendingParticles(getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.8D)).toLocation(player.getWorld()), 3, 0, 0, 0); - ParticleEffect.SMOKE_NORMAL.display(getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.8D)).toLocation(player.getWorld()), 3, 0, 0, 0, 0.01); - JCMethods.emitLight(getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.8D)).toLocation(player.getWorld())); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public List getLocations() { - List list = shots.stream().map(shot -> shot.location).collect(Collectors.toList()); - list.add(getRightHandPos()); - return list; - } - - @Override - public void handleCollision(Collision collision) { - if (collision.isRemovingFirst()) { - Optional collidedShot = shots.stream().filter(shot -> shot.location.equals(collision.getLocationFirst())).findAny(); - - collidedShot.ifPresent(shots::remove); - } else { - CoreAbility second = collision.getAbilitySecond(); - if (second instanceof AirShield) { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - boolean reflect = config.getBoolean("Abilities.Fire.FireShots.Collisions.AirShield.Reflect", true); - - if (reflect) { - Optional collidedShot = shots.stream().filter(shot -> shot.location.equals(collision.getLocationFirst())).findAny(); - - if (collidedShot.isPresent()) { - FireShot fireShot = collidedShot.get(); - AirShield shield = (AirShield) second; - - fireShot.direction = player.getLocation().getDirection().clone(); - AirShieldReflector.reflect(shield, fireShot.location, fireShot.direction); - } - } - } - } - } - - @Override - public String getName() { - return "FireShots"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Fire.FireShots.Description"); - } - - public List getShots() { - return shots; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public int getStartAmount() { - return startAmount; - } - - public void setStartAmount(int startAmount) { - this.startAmount = startAmount; - } - - public int getFireticks() { - return fireticks; - } - - public void setFireticks(int fireticks) { - this.fireticks = fireticks; - } - - public int getRange() { - return range; - } - - public void setRange(int range) { - this.range = range; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - @Override - public double getCollisionRadius() { - return collisionRadius; - } - - public void setCollisionRadius(double collisionRadius) { - this.collisionRadius = collisionRadius; - } - - public int getAmount() { - return amount; - } - - public void setAmount(int amount) { - this.amount = amount; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Fire.FireShots.Enabled"); - } -} + private final List shots = new ArrayList<>(); + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute("MaxShots") + private int startAmount; + @Attribute(Attribute.FIRE_TICK) + private int fireticks; + @Attribute(Attribute.RANGE) + private int range; + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute("CollisionRadius") + private double collisionRadius; + private Boolean flameInMainHand = null; + + public int amount; + + public FireShots(Player player){ + super(player); + + if (!bPlayer.canBend(this) || hasAbility(player, FireShots.class)) { + return; + } + + if (!player.hasGravity()) + player.setGravity(true); + + setFields(); + + amount = startAmount; + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Fire.FireShots.Cooldown"); + startAmount = config.getInt("Abilities.Fire.FireShots.FireBalls"); + fireticks = config.getInt("Abilities.Fire.FireShots.FireDuration"); + range = config.getInt("Abilities.Fire.FireShots.Range"); + damage = config.getDouble("Abilities.Fire.FireShots.Damage"); + collisionRadius = config.getDouble("Abilities.Fire.FireShots.CollisionRadius"); + + applyModifiers(); + } + + private void applyModifiers() { + if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { + cooldown *= BlueFireAbility.getCooldownFactor(); + range *= BlueFireAbility.getRangeFactor(); + damage *= BlueFireAbility.getDamageFactor(); + } + + if (isDay(player.getWorld())) { + cooldown -= ((long) getDayFactor(cooldown) - cooldown); + range = (int) getDayFactor(range); + damage = getDayFactor(damage); + } + } + + public class FireShot { + + private final Ability ability; + private final Player player; + private Location location; + private final int range; + private final int fireTicks; + private double distanceTravelled; + private final double damage; + private Vector direction = null; + + public FireShot(Ability ability, Player player, Location location, int range, int fireTicks, double damage) { + this.ability = ability; + this.player = player; + this.location = location; + this.range = range; + this.fireTicks = fireTicks; + this.damage = damage; + } + + public boolean progress() { + if (player.isDead() || !player.isOnline()) { + return false; + } + if (distanceTravelled >= range) { + return false; + } + for (int i = 0; i < 2; i++) { + distanceTravelled ++; + if (distanceTravelled >= range) + return false; + + Vector dir = direction; + if (dir == null) { + dir = this.player.getLocation().getDirection().clone(); + } + + location = location.add(dir); + + if (GeneralMethods.isSolid(location.getBlock()) || isWater(location.getBlock())){ + return false; + } + + if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { + ParticleEffect.SOUL_FIRE_FLAME.display(location, 5, 0.0, 0.0, 0.0, 0.02); + } else { + ParticleEffect.FLAME.display(location, 5, 0.0, 0.0, 0.0, 0.02); + } + ParticleEffect.SMOKE_NORMAL.display(location, 2, 0.0, 0.0, 0.0, 0.01); + + JCMethods.emitLight(location); + + Sphere collider = new Sphere(location.toVector(), collisionRadius); + + boolean hit = CollisionDetector.checkEntityCollisions(player, collider, (entity) -> { + DamageHandler.damageEntity(entity, damage, ability); + FireTick.set(entity, Math.round(fireTicks / 50F)); + new FireDamageTimer(entity, player, FireShots.this); + return true; + }); + + if (hit) { + return false; + } + } + return true; + } + + public Ability getAbility() { + return ability; + } + + public Player getPlayer() { + return player; + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + + public int getRange() { + return range; + } + + public int getFireTicks() { + return fireTicks; + } + + public double getDistanceTravelled() { + return distanceTravelled; + } + + public void setDistanceTravelled(double distanceTravelled) { + this.distanceTravelled = distanceTravelled; + } + + public double getDamage() { + return damage; + } + + public Vector getDirection() { + return direction; + } + + public void setDirection(Vector direction) { + this.direction = direction; + } + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + + if (!bPlayer.canBendIgnoreCooldowns(this)) { + amount = 0; + if (!bPlayer.isOnCooldown(this)) { + bPlayer.addCooldown(this); + } + } + + shots.removeIf(shot -> !shot.progress()); + + if (amount <= 0 && shots.isEmpty()) { + remove(); + return; + } + + if (amount > 0) { + displayFireBalls(); + } + } + + public static void fireShot(Player player) { + FireShots fs = getAbility(player, FireShots.class); + if (fs != null) { + fs.fireShot(); + } + } + + public static void swapHands(Player player) { + FireShots fs = getAbility(player, FireShots.class); + if (fs == null) + return; + if (fs.flameInMainHand == null) + fs.flameInMainHand = true; + else fs.flameInMainHand = !fs.flameInMainHand; + } + + public void fireShot() { + if (amount >= 1) { + if (--amount <= 0) { + bPlayer.addCooldown(this); + } + shots.add(new FireShot(this, player, getRightHandPos(), range, fireticks, damage)); + } + } + + public Location getRightHandPos() { + return (player.getMainHand()==MainHand.RIGHT == ((flameInMainHand == null) || flameInMainHand) ? + GeneralMethods.getRightSide(player.getLocation(), .55) : + GeneralMethods.getLeftSide(player.getLocation(), .55)).add(0, 1.2, 0); + } + + private void displayFireBalls() { + playFirebendingParticles(getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.8D)).toLocation(player.getWorld()), 3, 0, 0, 0); + ParticleEffect.SMOKE_NORMAL.display(getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.8D)).toLocation(player.getWorld()), 3, 0, 0, 0, 0.01); + JCMethods.emitLight(getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.8D)).toLocation(player.getWorld())); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public List getLocations() { + List list = shots.stream().map(shot -> shot.location).collect(Collectors.toList()); + list.add(getRightHandPos()); + return list; + } + + @Override + public void handleCollision(Collision collision) { + if (collision.isRemovingFirst()) { + Optional collidedShot = shots.stream().filter(shot -> shot.location.equals(collision.getLocationFirst())).findAny(); + + collidedShot.ifPresent(shots::remove); + } else { + CoreAbility second = collision.getAbilitySecond(); + if (second instanceof AirShield) { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + boolean reflect = config.getBoolean("Abilities.Fire.FireShots.Collisions.AirShield.Reflect", true); + + if (reflect) { + Optional collidedShot = shots.stream().filter(shot -> shot.location.equals(collision.getLocationFirst())).findAny(); + + if (collidedShot.isPresent()) { + FireShot fireShot = collidedShot.get(); + AirShield shield = (AirShield) second; + + fireShot.direction = player.getLocation().getDirection().clone(); + AirShieldReflector.reflect(shield, fireShot.location, fireShot.direction); + } + } + } + } + } + + @Override + public String getName() { + return "FireShots"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Fire.FireShots.Description"); + } + + public List getShots() { + return shots; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public int getStartAmount() { + return startAmount; + } + + public void setStartAmount(int startAmount) { + this.startAmount = startAmount; + } + + public int getFireticks() { + return fireticks; + } + + public void setFireticks(int fireticks) { + this.fireticks = fireticks; + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + @Override + public double getCollisionRadius() { + return collisionRadius; + } + + public void setCollisionRadius(double collisionRadius) { + this.collisionRadius = collisionRadius; + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Fire.FireShots.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/firebending/FireSki.java b/src/com/jedk1/jedcore/ability/firebending/FireSki.java index 0b5648d..d43de8a 100644 --- a/src/com/jedk1/jedcore/ability/firebending/FireSki.java +++ b/src/com/jedk1/jedcore/ability/firebending/FireSki.java @@ -12,7 +12,6 @@ import com.projectkorra.projectkorra.ability.FireAbility; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.util.ParticleEffect; - import org.bukkit.Location; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; diff --git a/src/com/jedk1/jedcore/ability/firebending/LightningBurst.java b/src/com/jedk1/jedcore/ability/firebending/LightningBurst.java index 8a20c8c..270f657 100644 --- a/src/com/jedk1/jedcore/ability/firebending/LightningBurst.java +++ b/src/com/jedk1/jedcore/ability/firebending/LightningBurst.java @@ -9,7 +9,6 @@ import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.configuration.ConfigurationSection; @@ -23,342 +22,348 @@ public class LightningBurst extends LightningAbility implements AddonAbility { - private static final ConcurrentHashMap BOLTS = new ConcurrentHashMap<>(); - - Random rand = new Random(); - @Attribute(Attribute.COOLDOWN) - private long cooldown, avatarCooldown; - @Attribute(Attribute.CHARGE_DURATION) - private long chargeUp, avatarChargeup; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute(Attribute.RADIUS) - private double radius; - - private boolean charged; - private static int ID = Integer.MIN_VALUE; - - public LightningBurst(Player player) { - super(player); - if (!bPlayer.canBend(this) || hasAbility(player, LightningBurst.class)) { - return; - } - - setFields(); - if (bPlayer.isAvatarState() || JCMethods.isSozinsComet(player.getWorld())) { - chargeUp = avatarChargeup; - cooldown = avatarCooldown; - } - - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Fire.LightningBurst.Cooldown"); - chargeUp = config.getLong("Abilities.Fire.LightningBurst.ChargeUp"); - avatarCooldown = config.getLong("Abilities.Fire.LightningBurst.AvatarCooldown"); - avatarChargeup = config.getLong("Abilities.Fire.LightningBurst.AvatarChargeUp"); - damage = config.getDouble("Abilities.Fire.LightningBurst.Damage"); - radius = config.getDouble("Abilities.Fire.LightningBurst.Radius"); - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - if (!bPlayer.canBendIgnoreCooldowns(this)) { - remove(); - return; - } - if (RegionProtection.isRegionProtected(player, player.getLocation(), this)) { - remove(); - return; - } - if (!player.isSneaking()) { - if (!isCharging()) { - Location fake = player.getLocation().add(0, -2, 0); - fake.setPitch(0); - for (int i = -180; i < 180; i += 55) { - fake.setYaw(i); - for (double j = -180; j <= 180; j += 55) { - Location temp = fake.clone(); - Vector dir = fake.getDirection().clone().multiply(2 * Math.cos(Math.toRadians(j))); - temp.add(dir); - temp.setY(temp.getY() + 2 + (2 * Math.sin(Math.toRadians(j)))); - dir = GeneralMethods.getDirection(player.getLocation().add(0, 0, 0), temp); - spawnBolt(player.getLocation().clone().add(0, 1, 0).setDirection(dir), radius, 1, 20, true); - } - } - bPlayer.addCooldown(this); - } - remove(); - } else if (System.currentTimeMillis() > getStartTime() + chargeUp){ - setCharging(false); - displayCharging(); - } - } - - private void spawnBolt(Location location, double max, double gap, int arc, boolean doDamage) { - int id = ID; - BOLTS.put(id, new Bolt(this, location, id, max, gap, arc, doDamage)); - if (ID == Integer.MAX_VALUE) - ID = Integer.MIN_VALUE; - ID++; - } - - private void displayCharging() { - Location fake = player.getLocation().add(0, 0, 0); - fake.setPitch(0); - for (int i = -180; i < 180; i += 55) { - fake.setYaw(i); - for (double j = -180; j <= 180; j += 55) { - if (rand.nextInt(100) == 0) { - Location temp = fake.clone(); - Vector dir = fake.getDirection().clone().multiply(1.2 * Math.cos(Math.toRadians(j))); - temp.add(dir); - temp.setY(temp.getY() + 1.2 + (1.2 * Math.sin(Math.toRadians(j)))); - dir = GeneralMethods.getDirection(temp, player.getLocation().add(0, 1, 0)); - spawnBolt(temp.setDirection(dir), 1, 0.2, 20, false); - } - } - } - } - - public static void progressAll() { - BOLTS.values().forEach(Bolt::progress); - } - - public boolean isCharging() { - return !charged; - } - - public void setCharging(boolean charging) { - this.charged = !charging; - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "LightningBurst"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Fire.LightningBurst.Description"); - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getAvatarCooldown() { - return avatarCooldown; - } - - public void setAvatarCooldown(long avatarCooldown) { - this.avatarCooldown = avatarCooldown; - } - - public long getChargeUp() { - return chargeUp; - } - - public void setChargeUp(long chargeUp) { - this.chargeUp = chargeUp; - } - - public long getAvatarChargeup() { - return avatarChargeup; - } - - public void setAvatarChargeup(long avatarChargeup) { - this.avatarChargeup = avatarChargeup; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public double getRadius() { - return radius; - } - - public void setRadius(double radius) { - this.radius = radius; - } - - public boolean isCharged() { - return charged; - } - - public void setCharged(boolean charged) { - this.charged = charged; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Fire.LightningBurst.Enabled"); - } - - public class Bolt { - - private final LightningBurst ability; - private Location location; - private final float initYaw; - private final float initPitch; - private double step; - private final double max; - private final double gap; - private final int id; - private final int arc; - private final boolean doDamage; - - public Bolt(LightningBurst ability, Location location, int id, double max, double gap, int arc, boolean doDamage) { - this.ability = ability; - this.location = location; - this.id = id; - this.max = max; - this.arc = arc; - this.gap = gap; - this.doDamage = doDamage; - initYaw = location.getYaw(); - initPitch = location.getPitch(); - } - - private void progress() { - if (this.step >= max) { - BOLTS.remove(id); - return; - } - if (RegionProtection.isRegionProtected(player, location, LightningBurst.this) || !isTransparent(location.getBlock())) { - BOLTS.remove(id); - return; - } - double step = 0.2; - for (double i = 0; i < gap; i+= step) { - this.step += step; - location = location.add(location.getDirection().clone().multiply(step)); - - playLightningbendingParticle(location, 0f, 0f, 0f); - JCMethods.emitLight(location); - } - switch (rand.nextInt(3)) { - case 0: - location.setYaw(initYaw - arc); - break; - case 1: - location.setYaw(initYaw + arc); - break; - default: - location.setYaw(initYaw); - break; - } - switch (rand.nextInt(3)) { - case 0: - location.setPitch(initPitch - arc); - break; - case 1: - location.setPitch(initPitch + arc); - break; - default: - location.setPitch(initPitch); - break; - } - - if (rand.nextInt(3) == 0) { - location.getWorld().playSound(location, Sound.ENTITY_CREEPER_PRIMED, 1, 0); - } - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && doDamage) { - DamageHandler.damageEntity(entity, damage, ability); - } - } - } - - public LightningBurst getAbility() { - return ability; - } - - public Location getLocation() { - return location; - } - - public float getInitYaw() { - return initYaw; - } - - public float getInitPitch() { - return initPitch; - } - - public double getStep() { - return step; - } - - public double getMax() { - return max; - } - - public double getGap() { - return gap; - } - - public int getId() { - return id; - } - - public int getArc() { - return arc; - } - - public boolean isDoDamage() { - return doDamage; - } - } + private static final ConcurrentHashMap BOLTS = new ConcurrentHashMap<>(); + + Random rand = new Random(); + @Attribute(Attribute.COOLDOWN) + private long cooldown, avatarCooldown; + @Attribute(Attribute.CHARGE_DURATION) + private long chargeUp, avatarChargeup; + @Attribute(Attribute.DAMAGE) + private double damage; + @Attribute(Attribute.RADIUS) + private double radius; + + private boolean charged; + private static int ID = Integer.MIN_VALUE; + + private float soundVolume; + private int soundInterval; + + public LightningBurst(Player player) { + super(player); + if (!bPlayer.canBend(this) || hasAbility(player, LightningBurst.class)) { + return; + } + + setFields(); + if (bPlayer.isAvatarState() || JCMethods.isSozinsComet(player.getWorld())) { + chargeUp = avatarChargeup; + cooldown = avatarCooldown; + } + + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Fire.LightningBurst.Cooldown"); + chargeUp = config.getLong("Abilities.Fire.LightningBurst.ChargeUp"); + avatarCooldown = config.getLong("Abilities.Fire.LightningBurst.AvatarCooldown"); + avatarChargeup = config.getLong("Abilities.Fire.LightningBurst.AvatarChargeUp"); + damage = config.getDouble("Abilities.Fire.LightningBurst.Damage"); + radius = config.getDouble("Abilities.Fire.LightningBurst.Radius"); + + soundVolume = (float) config.getDouble("Abilities.Fire.LightningBurst.Sound.Volume"); + soundInterval = config.getInt("Abilities.Fire.LightningBurst.Sound.Interval"); + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + if (!bPlayer.canBendIgnoreCooldowns(this)) { + remove(); + return; + } + if (RegionProtection.isRegionProtected(player, player.getLocation(), this)) { + remove(); + return; + } + if (!player.isSneaking()) { + if (!isCharging()) { + Location fake = player.getLocation().add(0, -2, 0); + fake.setPitch(0); + for (int i = -180; i < 180; i += 55) { + fake.setYaw(i); + for (double j = -180; j <= 180; j += 55) { + Location temp = fake.clone(); + Vector dir = fake.getDirection().clone().multiply(2 * Math.cos(Math.toRadians(j))); + temp.add(dir); + temp.setY(temp.getY() + 2 + (2 * Math.sin(Math.toRadians(j)))); + dir = GeneralMethods.getDirection(player.getLocation().add(0, 0, 0), temp); + spawnBolt(player.getLocation().clone().add(0, 1, 0).setDirection(dir), radius, 1, 20, true); + } + } + bPlayer.addCooldown(this); + } + remove(); + } else if (System.currentTimeMillis() > getStartTime() + chargeUp){ + setCharging(false); + displayCharging(); + } + } + + private void spawnBolt(Location location, double max, double gap, int arc, boolean doDamage) { + int id = ID; + BOLTS.put(id, new Bolt(this, location, id, max, gap, arc, doDamage)); + if (ID == Integer.MAX_VALUE) + ID = Integer.MIN_VALUE; + ID++; + } + + private void displayCharging() { + Location fake = player.getLocation().add(0, 0, 0); + fake.setPitch(0); + for (int i = -180; i < 180; i += 55) { + fake.setYaw(i); + for (double j = -180; j <= 180; j += 55) { + if (rand.nextInt(100) == 0) { + Location temp = fake.clone(); + Vector dir = fake.getDirection().clone().multiply(1.2 * Math.cos(Math.toRadians(j))); + temp.add(dir); + temp.setY(temp.getY() + 1.2 + (1.2 * Math.sin(Math.toRadians(j)))); + dir = GeneralMethods.getDirection(temp, player.getLocation().add(0, 1, 0)); + spawnBolt(temp.setDirection(dir), 1, 0.2, 20, false); + } + } + } + } + + public static void progressAll() { + BOLTS.values().forEach(Bolt::progress); + } + + public boolean isCharging() { + return !charged; + } + + public void setCharging(boolean charging) { + this.charged = !charging; + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "LightningBurst"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Fire.LightningBurst.Description"); + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public long getAvatarCooldown() { + return avatarCooldown; + } + + public void setAvatarCooldown(long avatarCooldown) { + this.avatarCooldown = avatarCooldown; + } + + public long getChargeUp() { + return chargeUp; + } + + public void setChargeUp(long chargeUp) { + this.chargeUp = chargeUp; + } + + public long getAvatarChargeup() { + return avatarChargeup; + } + + public void setAvatarChargeup(long avatarChargeup) { + this.avatarChargeup = avatarChargeup; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public double getRadius() { + return radius; + } + + public void setRadius(double radius) { + this.radius = radius; + } + + public boolean isCharged() { + return charged; + } + + public void setCharged(boolean charged) { + this.charged = charged; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Fire.LightningBurst.Enabled"); + } + + public class Bolt { + + private final LightningBurst ability; + private Location location; + private final float initYaw; + private final float initPitch; + private double step; + private final double max; + private final double gap; + private final int id; + private final int arc; + private final boolean doDamage; + + public Bolt(LightningBurst ability, Location location, int id, double max, double gap, int arc, boolean doDamage) { + this.ability = ability; + this.location = location; + this.id = id; + this.max = max; + this.arc = arc; + this.gap = gap; + this.doDamage = doDamage; + initYaw = location.getYaw(); + initPitch = location.getPitch(); + } + + private void progress() { + if (this.step >= max) { + BOLTS.remove(id); + return; + } + if (RegionProtection.isRegionProtected(player, location, LightningBurst.this) || !isTransparent(location.getBlock())) { + BOLTS.remove(id); + return; + } + double step = 0.2; + for (double i = 0; i < gap; i+= step) { + this.step += step; + location = location.add(location.getDirection().clone().multiply(step)); + + playLightningbendingParticle(location, 0f, 0f, 0f); + JCMethods.emitLight(location); + } + switch (rand.nextInt(3)) { + case 0: + location.setYaw(initYaw - arc); + break; + case 1: + location.setYaw(initYaw + arc); + break; + default: + location.setYaw(initYaw); + break; + } + switch (rand.nextInt(3)) { + case 0: + location.setPitch(initPitch - arc); + break; + case 1: + location.setPitch(initPitch + arc); + break; + default: + location.setPitch(initPitch); + break; + } + + if (rand.nextInt(soundInterval) == 0) { + location.getWorld().playSound(location, Sound.ENTITY_BEE_HURT, soundVolume, 0.2f); + } + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 2)) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && doDamage) { + DamageHandler.damageEntity(entity, damage, ability); + } + } + } + + public LightningBurst getAbility() { + return ability; + } + + public Location getLocation() { + return location; + } + + public float getInitYaw() { + return initYaw; + } + + public float getInitPitch() { + return initPitch; + } + + public double getStep() { + return step; + } + + public double getMax() { + return max; + } + + public double getGap() { + return gap; + } + + public int getId() { + return id; + } + + public int getArc() { + return arc; + } + + public boolean isDoDamage() { + return doDamage; + } + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/passive/WallRun.java b/src/com/jedk1/jedcore/ability/passive/WallRun.java index a60418f..816dab9 100644 --- a/src/com/jedk1/jedcore/ability/passive/WallRun.java +++ b/src/com/jedk1/jedcore/ability/passive/WallRun.java @@ -10,7 +10,6 @@ import com.projectkorra.projectkorra.ability.ChiAbility; import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.util.ParticleEffect; - import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; diff --git a/src/com/jedk1/jedcore/ability/waterbending/BloodPuppet.java b/src/com/jedk1/jedcore/ability/waterbending/BloodPuppet.java index 6e3bf14..7a48f32 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/BloodPuppet.java +++ b/src/com/jedk1/jedcore/ability/waterbending/BloodPuppet.java @@ -1,11 +1,17 @@ package com.jedk1.jedcore.ability.waterbending; -import java.util.*; - +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; +import com.projectkorra.projectkorra.BendingPlayer; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.BloodAbility; import com.projectkorra.projectkorra.ability.ElementalAbility; import com.projectkorra.projectkorra.attribute.Attribute; +import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.region.RegionProtection; +import com.projectkorra.projectkorra.util.DamageHandler; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; @@ -14,498 +20,493 @@ import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.util.Vector; -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.BendingPlayer; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.BloodAbility; -import com.projectkorra.projectkorra.command.Commands; -import com.projectkorra.projectkorra.util.DamageHandler; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; public class BloodPuppet extends BloodAbility implements AddonAbility { - private boolean nightOnly; - private boolean fullMoonOnly; - private boolean undeadMobs; - private boolean bloodPuppetThroughBlocks; - private boolean requireBound; - private int distance; - @Attribute(Attribute.DURATION) - private long holdTime; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - - private long endTime; - - public LivingEntity puppet; - private long lastDamageTime = 0; - - Random rand = new Random(); - - public BloodPuppet(Player player) { - super(player); - if (!isEligible(player, true)) { - return; - } - - setFields(); - endTime = System.currentTimeMillis() + holdTime; - - if (grab()) { - start(); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - nightOnly = config.getBoolean("Abilities.Water.BloodPuppet.NightOnly"); - fullMoonOnly = config.getBoolean("Abilities.Water.BloodPuppet.FullMoonOnly"); - undeadMobs = config.getBoolean("Abilities.Water.BloodPuppet.UndeadMobs"); - bloodPuppetThroughBlocks = config.getBoolean("Abilities.Water.BloodPuppet.IgnoreWalls"); - requireBound = config.getBoolean("Abilities.Water.BloodPuppet.RequireBound"); - distance = config.getInt("Abilities.Water.BloodPuppet.Distance"); - holdTime = config.getLong("Abilities.Water.BloodPuppet.HoldTime"); - cooldown = config.getLong("Abilities.Water.BloodPuppet.Cooldown"); - } - - public boolean isEligible(Player player, boolean hasAbility) { - if (!bPlayer.canBend(this) || !bPlayer.canBloodbend() || (hasAbility && hasAbility(player, BloodPuppet.class))) { - return false; - } - if (nightOnly && !isNight(player.getWorld()) && !bPlayer.canBloodbendAtAnytime()) { - return false; - } - return !fullMoonOnly || isFullMoon(player.getWorld()) || bPlayer.canBloodbendAtAnytime(); - } - - private boolean canAttack() { - switch (puppet.getType()) { - case SKELETON: - case SPIDER: - case GIANT: - case ZOMBIE: - case SLIME: - case GHAST: - case PIGLIN: - case ZOMBIFIED_PIGLIN: - case ENDERMAN: - case CAVE_SPIDER: - case SILVERFISH: - case BLAZE: - case MAGMA_CUBE: - case WITCH: - case ENDERMITE: - case DROWNED: - case PLAYER: - return true; - default: - return false; - } - } - - private boolean grab() { - List entities = new ArrayList<>(); - for (int i = 1; i < distance; i++) { - Location location; - if (bloodPuppetThroughBlocks) { - location = player.getTargetBlock(null, i).getLocation(); - } else { - location = GeneralMethods.getTargetedLocation(player, i, ElementalAbility.getTransparentMaterials()); - } - entities = GeneralMethods.getEntitiesAroundPoint(location, 1.7); - entities.remove(player); - if (!entities.isEmpty() && !entities.contains(player)) { - break; - } - } - if (entities.isEmpty()) { - return false; - } - Entity e = entities.get(0); - - if (e == null) - return false; - - if (!(e instanceof LivingEntity)) - return false; - - if (!undeadMobs && GeneralMethods.isUndead(e)) - return false; - - if ((e instanceof Player) && !canBeBloodbent((Player) e)) { - return false; - } - if (RegionProtection.isRegionProtected(player, e.getLocation(), this)) { - return false; - } - - for (BloodPuppet bb : getAbilities(BloodPuppet.class)) { - if (bb.puppet.getEntityId() == e.getEntityId()) { - return false; - } - } - - puppet = (LivingEntity) e; - DamageHandler.damageEntity(puppet, 0, this); - if (puppet instanceof Creature) - ((Creature) puppet).setTarget(null); - - if (e instanceof Player && BendingPlayer.getBendingPlayer((Player) e) != null) { - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer((Player) e); - bPlayer.blockChi(); - } - - return true; - } - - private boolean canBeBloodbent(Player player) { - if (Commands.invincible.contains(player.getName())) { - return false; - } - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - if (requireBound) { - if (bPlayer.getAbilities().containsValue("Bloodbending")) { - return false; - } - return !bPlayer.getAbilities().containsValue("BloodPuppet"); - } else { - if (bPlayer.canBind(getAbility("Bloodbending")) && bPlayer.canBloodbend()) { - return isDay(player.getWorld()) && !bPlayer.canBloodbendAtAnytime(); - } - } - return true; - } - - public static void attack(Player player) { - if (hasAbility(player, BloodPuppet.class)) { - getAbility(player, BloodPuppet.class).attack(); - } - } - - private void attack() { - if (!canAttack()) - return; - - long damageCd = 0; - if (System.currentTimeMillis() > lastDamageTime + damageCd) { - lastDamageTime = System.currentTimeMillis(); - - if (puppet instanceof Skeleton) { - Skeleton skelly = (Skeleton) puppet; - List nearby = GeneralMethods.getEntitiesAroundPoint(skelly.getLocation(), 5); - nearby.remove(puppet); - if (nearby.size() < 1) - return; - int randy = rand.nextInt(nearby.size()); - Entity target = nearby.get(randy); - if (target instanceof LivingEntity) { - LivingEntity e = (LivingEntity) target; - Location loc = puppet.getLocation().getBlock().getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()))).getLocation(); - Arrow a = puppet.getWorld().spawnArrow(loc, GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()), 0.6f, 12); - a.setShooter(puppet); - if (e instanceof Creature) - ((Creature) e).setTarget(puppet); - } - } - - else if (puppet instanceof Creeper) { - Creeper creep = (Creeper) puppet; - creep.setPowered(true); - } - - else if (puppet instanceof Ghast) { - Ghast gaga = (Ghast) puppet; - List nearby = GeneralMethods.getEntitiesAroundPoint(gaga.getLocation(), 5); - nearby.remove(puppet); - if (nearby.size() < 1) - return; - int randy = rand.nextInt(nearby.size()); - Entity target = nearby.get(randy); - if (target instanceof LivingEntity) { - LivingEntity e = (LivingEntity) target; - Location loc = puppet.getLocation().getBlock().getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()))).getLocation(); - Fireball fb = puppet.getWorld().spawn(loc, Fireball.class); - fb.setVelocity(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()).multiply(0.25)); - fb.setIsIncendiary(true); - fb.setShooter(puppet); - if (e instanceof Creature) - ((Creature) e).setTarget(puppet); - } - } - - else if (puppet instanceof Blaze) { - Blaze balawalaze = (Blaze) puppet; - List nearby = GeneralMethods.getEntitiesAroundPoint(balawalaze.getLocation(), 5); - nearby.remove(puppet); - if (nearby.size() < 1) - return; - int randy = rand.nextInt(nearby.size()); - Entity target = nearby.get(randy); - if (target instanceof LivingEntity) { - LivingEntity e = (LivingEntity) target; - Location loc = puppet.getLocation().getBlock().getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()))).getLocation(); - Fireball fb = puppet.getWorld().spawn(loc, Fireball.class); - fb.setVelocity(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()).multiply(0.5)); - fb.setShooter(puppet); - if (e instanceof Creature) - ((Creature) e).setTarget(puppet); - } - } - - else if (puppet instanceof Witch) { - Witch missmagus = (Witch) puppet; - List nearby = GeneralMethods.getEntitiesAroundPoint(missmagus.getLocation(), 5); - nearby.remove(puppet); - if (nearby.size() < 1) - return; - int randy = rand.nextInt(nearby.size()); - Entity target = nearby.get(randy); - if (target instanceof LivingEntity) { - LivingEntity e = (LivingEntity) target; - ThrownPotion tp = missmagus.launchProjectile(ThrownPotion.class, GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation())); - ItemStack potionItem = new ItemStack(Material.SPLASH_POTION, 1); - PotionMeta potion = (PotionMeta) potionItem.getItemMeta(); - potion.setBasePotionType(JedCore.plugin.getPotionEffectAdapter().getHarmingPotionType()); - potionItem.setItemMeta(potion); - tp.setItem(potionItem); - tp.setVelocity(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()).multiply(0.125)); - tp.setShooter(puppet); - if (e instanceof Creature) - ((Creature) e).setTarget(puppet); - } - } - - else { - for (Entity e : GeneralMethods.getEntitiesAroundPoint(puppet.getLocation(), 2)) { - if (e.getEntityId() == puppet.getEntityId()) - continue; - - if (e instanceof LivingEntity) { - int damage = 2; - if (puppet instanceof Player) { - Player p = (Player) puppet; - - switch (p.getInventory().getItemInMainHand().getType()) { - case WOODEN_SWORD: - case GOLDEN_SWORD: - damage = 5; - break; - case STONE_SWORD: - damage = 6; - break; - case IRON_SWORD: - damage = 7; - break; - case DIAMOND_SWORD: - damage = 8; - break; - default: - break; - } - } - ((LivingEntity) e).damage(damage, puppet); - if (e instanceof Creature) - ((Creature) e).setTarget(puppet); - } - } - } - } - } - - @Override - public void progress() { - if (player == null || !player.isOnline() || player.isDead()) { - remove(); - return; - } - if (!isEligible(player, false)) { - remove(); - return; - } - - if (!player.isSneaking()) { - remove(); - return; - } - - if (System.currentTimeMillis() > endTime) { - remove(); - return; - } - - if ((puppet instanceof Player && !((Player) puppet).isOnline()) || puppet.isDead()) { - remove(); - return; - } - - Location newLocation = puppet.getLocation(); - - Location location = GeneralMethods.getTargetedLocation(player, distance + 1); - double distance = location.distance(newLocation); - double dx, dy, dz; - dx = location.getX() - newLocation.getX(); - dy = location.getY() - newLocation.getY(); - dz = location.getZ() - newLocation.getZ(); - Vector vector = new Vector(dx, dy, dz); - if (distance > .5) { - puppet.setVelocity(vector.normalize().multiply(.5)); - } else { - puppet.setVelocity(new Vector(0, 0, 0)); - } - puppet.setFallDistance(0); - if (puppet instanceof Creature) { - ((Creature) puppet).setTarget(null); - } - AirAbility.breakBreathbendingHold(puppet); - } - - @Override - public void remove() { - if (player.isOnline()) { - bPlayer.addCooldown(this); - } - if (puppet instanceof Player && ((Player) puppet).isOnline()) { - BendingPlayer.getBendingPlayer((Player) puppet).unblockChi(); - } - super.remove(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "BloodPuppet"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Water.BloodPuppet.Description"); - } - - public boolean isNightOnly() { - return nightOnly; - } - - public void setNightOnly(boolean nightOnly) { - this.nightOnly = nightOnly; - } - - public boolean isFullMoonOnly() { - return fullMoonOnly; - } - - public void setFullMoonOnly(boolean fullMoonOnly) { - this.fullMoonOnly = fullMoonOnly; - } - - public boolean isUndeadMobs() { - return undeadMobs; - } - - public void setUndeadMobs(boolean undeadMobs) { - this.undeadMobs = undeadMobs; - } - - public boolean canBloodPuppetThroughBlocks() { - return bloodPuppetThroughBlocks; - } - - public void setCanBloodPuppetThroughBlocks(boolean bloodPuppetThroughBlocks) { - this.bloodPuppetThroughBlocks = bloodPuppetThroughBlocks; - } - - public boolean requiresBound() { - return requireBound; - } - - public void setRequireBound(boolean requireBound) { - this.requireBound = requireBound; - } - - public int getDistance() { - return distance; - } - - public void setDistance(int distance) { - this.distance = distance; - } - - public long getHoldTime() { - return holdTime; - } - - public void setHoldTime(long holdTime) { - this.holdTime = holdTime; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getEndTime() { - return endTime; - } - - public void setEndTime(long endTime) { - this.endTime = endTime; - } - - public LivingEntity getPuppet() { - return puppet; - } - - public void setPuppet(LivingEntity puppet) { - this.puppet = puppet; - } - - public long getLastDamageTime() { - return lastDamageTime; - } - - public void setLastDamageTime(long lastDamageTime) { - this.lastDamageTime = lastDamageTime; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Water.BloodPuppet.Enabled"); - } -} + private boolean nightOnly; + private boolean fullMoonOnly; + private boolean undeadMobs; + private boolean bloodPuppetThroughBlocks; + private boolean requireBound; + private int distance; + @Attribute(Attribute.DURATION) + private long holdTime; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + + private long endTime; + + public LivingEntity puppet; + private long lastDamageTime = 0; + + Random rand = new Random(); + + public BloodPuppet(Player player) { + super(player); + if (!isEligible(player, true)) { + return; + } + + setFields(); + endTime = System.currentTimeMillis() + holdTime; + + if (grab()) { + start(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + nightOnly = config.getBoolean("Abilities.Water.BloodPuppet.NightOnly"); + fullMoonOnly = config.getBoolean("Abilities.Water.BloodPuppet.FullMoonOnly"); + undeadMobs = config.getBoolean("Abilities.Water.BloodPuppet.UndeadMobs"); + bloodPuppetThroughBlocks = config.getBoolean("Abilities.Water.BloodPuppet.IgnoreWalls"); + requireBound = config.getBoolean("Abilities.Water.BloodPuppet.RequireBound"); + distance = config.getInt("Abilities.Water.BloodPuppet.Distance"); + holdTime = config.getLong("Abilities.Water.BloodPuppet.HoldTime"); + cooldown = config.getLong("Abilities.Water.BloodPuppet.Cooldown"); + } + + public boolean isEligible(Player player, boolean hasAbility) { + if (!bPlayer.canBend(this) || !bPlayer.canBloodbend() || (hasAbility && hasAbility(player, BloodPuppet.class))) { + return false; + } + if (nightOnly && !isNight(player.getWorld()) && !bPlayer.canBloodbendAtAnytime()) { + return false; + } + return !fullMoonOnly || isFullMoon(player.getWorld()) || bPlayer.canBloodbendAtAnytime(); + } + + private boolean canAttack() { + switch (puppet.getType()) { + case SKELETON: + case SPIDER: + case GIANT: + case ZOMBIE: + case SLIME: + case GHAST: + case PIGLIN: + case ZOMBIFIED_PIGLIN: + case ENDERMAN: + case CAVE_SPIDER: + case SILVERFISH: + case BLAZE: + case MAGMA_CUBE: + case WITCH: + case ENDERMITE: + case DROWNED: + case PLAYER: + return true; + default: + return false; + } + } + + private boolean grab() { + List entities = new ArrayList<>(); + for (int i = 1; i < distance; i++) { + Location location; + if (bloodPuppetThroughBlocks) { + location = player.getTargetBlock(null, i).getLocation(); + } else { + location = GeneralMethods.getTargetedLocation(player, i, ElementalAbility.getTransparentMaterials()); + } + entities = GeneralMethods.getEntitiesAroundPoint(location, 1.7); + entities.remove(player); + if (!entities.isEmpty() && !entities.contains(player)) { + break; + } + } + if (entities.isEmpty()) { + return false; + } + Entity e = entities.get(0); + + if (e == null) + return false; + + if (!(e instanceof LivingEntity)) + return false; + + if (!undeadMobs && GeneralMethods.isUndead(e)) + return false; + + if ((e instanceof Player) && !canBeBloodbent((Player) e)) { + return false; + } + if (RegionProtection.isRegionProtected(player, e.getLocation(), this)) { + return false; + } + + for (BloodPuppet bb : getAbilities(BloodPuppet.class)) { + if (bb.puppet.getEntityId() == e.getEntityId()) { + return false; + } + } + + puppet = (LivingEntity) e; + DamageHandler.damageEntity(puppet, 0, this); + if (puppet instanceof Creature) + ((Creature) puppet).setTarget(null); + + if (e instanceof Player && BendingPlayer.getBendingPlayer((Player) e) != null) { + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer((Player) e); + bPlayer.blockChi(); + } + + return true; + } + + private boolean canBeBloodbent(Player player) { + if (Commands.invincible.contains(player.getName())) { + return false; + } + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); + if (requireBound) { + if (bPlayer.getAbilities().containsValue("Bloodbending")) { + return false; + } + return !bPlayer.getAbilities().containsValue("BloodPuppet"); + } else { + if (bPlayer.canBind(getAbility("Bloodbending")) && bPlayer.canBloodbend()) { + return isDay(player.getWorld()) && !bPlayer.canBloodbendAtAnytime(); + } + } + return true; + } + + public static void attack(Player player) { + if (hasAbility(player, BloodPuppet.class)) { + getAbility(player, BloodPuppet.class).attack(); + } + } + + private void attack() { + if (!canAttack()) + return; + + long damageCd = 0; + if (System.currentTimeMillis() > lastDamageTime + damageCd) { + lastDamageTime = System.currentTimeMillis(); + + if (puppet instanceof Skeleton) { + Skeleton skelly = (Skeleton) puppet; + List nearby = GeneralMethods.getEntitiesAroundPoint(skelly.getLocation(), 5); + nearby.remove(puppet); + if (nearby.size() < 1) + return; + int randy = rand.nextInt(nearby.size()); + Entity target = nearby.get(randy); + if (target instanceof LivingEntity) { + LivingEntity e = (LivingEntity) target; + Location loc = puppet.getLocation().getBlock().getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()))).getLocation(); + Arrow a = puppet.getWorld().spawnArrow(loc, GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()), 0.6f, 12); + a.setShooter(puppet); + if (e instanceof Creature) + ((Creature) e).setTarget(puppet); + } + } + + else if (puppet instanceof Creeper) { + Creeper creep = (Creeper) puppet; + creep.setPowered(true); + } + + else if (puppet instanceof Ghast) { + Ghast gaga = (Ghast) puppet; + List nearby = GeneralMethods.getEntitiesAroundPoint(gaga.getLocation(), 5); + nearby.remove(puppet); + if (nearby.size() < 1) + return; + int randy = rand.nextInt(nearby.size()); + Entity target = nearby.get(randy); + if (target instanceof LivingEntity) { + LivingEntity e = (LivingEntity) target; + Location loc = puppet.getLocation().getBlock().getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()))).getLocation(); + Fireball fb = puppet.getWorld().spawn(loc, Fireball.class); + fb.setVelocity(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()).multiply(0.25)); + fb.setIsIncendiary(true); + fb.setShooter(puppet); + if (e instanceof Creature) + ((Creature) e).setTarget(puppet); + } + } + + else if (puppet instanceof Blaze) { + Blaze balawalaze = (Blaze) puppet; + List nearby = GeneralMethods.getEntitiesAroundPoint(balawalaze.getLocation(), 5); + nearby.remove(puppet); + if (nearby.size() < 1) + return; + int randy = rand.nextInt(nearby.size()); + Entity target = nearby.get(randy); + if (target instanceof LivingEntity) { + LivingEntity e = (LivingEntity) target; + Location loc = puppet.getLocation().getBlock().getRelative(GeneralMethods.getCardinalDirection(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()))).getLocation(); + Fireball fb = puppet.getWorld().spawn(loc, Fireball.class); + fb.setVelocity(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()).multiply(0.5)); + fb.setShooter(puppet); + if (e instanceof Creature) + ((Creature) e).setTarget(puppet); + } + } + + else if (puppet instanceof Witch) { + Witch missmagus = (Witch) puppet; + List nearby = GeneralMethods.getEntitiesAroundPoint(missmagus.getLocation(), 5); + nearby.remove(puppet); + if (nearby.size() < 1) + return; + int randy = rand.nextInt(nearby.size()); + Entity target = nearby.get(randy); + if (target instanceof LivingEntity) { + LivingEntity e = (LivingEntity) target; + ThrownPotion tp = missmagus.launchProjectile(ThrownPotion.class, GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation())); + ItemStack potionItem = new ItemStack(Material.SPLASH_POTION, 1); + PotionMeta potion = (PotionMeta) potionItem.getItemMeta(); + potion.setBasePotionType(JedCore.plugin.getPotionEffectAdapter().getHarmingPotionType()); + potionItem.setItemMeta(potion); + tp.setItem(potionItem); + tp.setVelocity(GeneralMethods.getDirection(puppet.getEyeLocation(), e.getEyeLocation()).multiply(0.125)); + tp.setShooter(puppet); + if (e instanceof Creature) + ((Creature) e).setTarget(puppet); + } + } + + else { + for (Entity e : GeneralMethods.getEntitiesAroundPoint(puppet.getLocation(), 2)) { + if (e.getEntityId() == puppet.getEntityId()) + continue; + + if (e instanceof LivingEntity) { + int damage = 2; + if (puppet instanceof Player) { + Player p = (Player) puppet; + + switch (p.getInventory().getItemInMainHand().getType()) { + case WOODEN_SWORD: + case GOLDEN_SWORD: + damage = 5; + break; + case STONE_SWORD: + damage = 6; + break; + case IRON_SWORD: + damage = 7; + break; + case DIAMOND_SWORD: + damage = 8; + break; + default: + break; + } + } + ((LivingEntity) e).damage(damage, puppet); + if (e instanceof Creature) + ((Creature) e).setTarget(puppet); + } + } + } + } + } + + @Override + public void progress() { + if (player == null || !player.isOnline() || player.isDead()) { + remove(); + return; + } + if (!isEligible(player, false)) { + remove(); + return; + } + + if (!player.isSneaking()) { + remove(); + return; + } + + if (System.currentTimeMillis() > endTime) { + remove(); + return; + } + + if ((puppet instanceof Player && !((Player) puppet).isOnline()) || puppet.isDead()) { + remove(); + return; + } + + Location newLocation = puppet.getLocation(); + + Location location = GeneralMethods.getTargetedLocation(player, distance + 1); + double distance = location.distance(newLocation); + double dx, dy, dz; + dx = location.getX() - newLocation.getX(); + dy = location.getY() - newLocation.getY(); + dz = location.getZ() - newLocation.getZ(); + Vector vector = new Vector(dx, dy, dz); + if (distance > .5) { + puppet.setVelocity(vector.normalize().multiply(.5)); + } else { + puppet.setVelocity(new Vector(0, 0, 0)); + } + puppet.setFallDistance(0); + if (puppet instanceof Creature) { + ((Creature) puppet).setTarget(null); + } + AirAbility.breakBreathbendingHold(puppet); + } + + @Override + public void remove() { + if (player.isOnline()) { + bPlayer.addCooldown(this); + } + if (puppet instanceof Player && ((Player) puppet).isOnline()) { + BendingPlayer.getBendingPlayer((Player) puppet).unblockChi(); + } + super.remove(); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "BloodPuppet"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Water.BloodPuppet.Description"); + } + + public boolean isNightOnly() { + return nightOnly; + } + + public void setNightOnly(boolean nightOnly) { + this.nightOnly = nightOnly; + } + + public boolean isFullMoonOnly() { + return fullMoonOnly; + } + + public void setFullMoonOnly(boolean fullMoonOnly) { + this.fullMoonOnly = fullMoonOnly; + } + + public boolean isUndeadMobs() { + return undeadMobs; + } + + public void setUndeadMobs(boolean undeadMobs) { + this.undeadMobs = undeadMobs; + } + + public boolean canBloodPuppetThroughBlocks() { + return bloodPuppetThroughBlocks; + } + + public void setCanBloodPuppetThroughBlocks(boolean bloodPuppetThroughBlocks) { + this.bloodPuppetThroughBlocks = bloodPuppetThroughBlocks; + } + + public boolean requiresBound() { + return requireBound; + } + + public void setRequireBound(boolean requireBound) { + this.requireBound = requireBound; + } + + public int getDistance() { + return distance; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + public long getHoldTime() { + return holdTime; + } + + public void setHoldTime(long holdTime) { + this.holdTime = holdTime; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } + + public LivingEntity getPuppet() { + return puppet; + } + + public void setPuppet(LivingEntity puppet) { + this.puppet = puppet; + } + + public long getLastDamageTime() { + return lastDamageTime; + } + + public void setLastDamageTime(long lastDamageTime) { + this.lastDamageTime = lastDamageTime; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Water.BloodPuppet.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/Bloodbending.java b/src/com/jedk1/jedcore/ability/waterbending/Bloodbending.java index 5c2e122..122265a 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/Bloodbending.java +++ b/src/com/jedk1/jedcore/ability/waterbending/Bloodbending.java @@ -14,7 +14,6 @@ import com.projectkorra.projectkorra.object.HorizontalVelocityTracker; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.*; @@ -26,352 +25,352 @@ public class Bloodbending extends BloodAbility implements AddonAbility { - private boolean nightOnly; - private boolean fullMoonOnly; - private boolean undeadMobs; - private boolean bloodbendingThroughBlocks; - private boolean requireBound; - private int distance; - @Attribute(Attribute.DURATION) - private long holdTime; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - - private long time; - public LivingEntity victim; - private BendingPlayer victimBPlayer; - private boolean grabbed; - - public Bloodbending(Player player) { - super(player); - if (this.player == null || !isEligible(player, true)) { - return; - } - setFields(); - time = System.currentTimeMillis() + holdTime; - if (grab()) { - start(); - } - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - nightOnly = config.getBoolean("Abilities.Water.Bloodbending.NightOnly"); - fullMoonOnly = config.getBoolean("Abilities.Water.Bloodbending.FullMoonOnly"); - undeadMobs = config.getBoolean("Abilities.Water.Bloodbending.UndeadMobs"); - bloodbendingThroughBlocks = config.getBoolean("Abilities.Water.Bloodbending.IgnoreWalls"); - requireBound = config.getBoolean("Abilities.Water.Bloodbending.RequireBound"); - distance = config.getInt("Abilities.Water.Bloodbending.Distance"); - holdTime = config.getLong("Abilities.Water.Bloodbending.HoldTime"); - cooldown = config.getLong("Abilities.Water.Bloodbending.Cooldown"); - } - - public boolean isEligible(Player player, boolean hasAbility) { - if (!bPlayer.canBend(this) || !bPlayer.canBloodbend() || (hasAbility && hasAbility(player, Bloodbending.class))) { - return false; - } - if (nightOnly && !isNight(player.getWorld()) && !bPlayer.canBloodbendAtAnytime()) { - return false; - } - return !fullMoonOnly || isFullMoon(player.getWorld()) || bPlayer.canBloodbendAtAnytime(); - } - - public static void launch(Player player) { - if (hasAbility(player, Bloodbending.class)) { - getAbility(player, Bloodbending.class).launch(); - } - } - - private void launch() { - if (Arrays.asList(ElementalAbility.getTransparentMaterials()).contains(player.getEyeLocation().getBlock().getType())) { - Vector direction = GeneralMethods.getDirection(player.getEyeLocation(), GeneralMethods.getTargetedLocation(player, 20, ElementalAbility.getTransparentMaterials())).normalize().multiply(3); - if (!victim.isDead()) { - victim.setVelocity(direction); - - new HorizontalVelocityTracker(victim, player, 200L, this); - new ThrownEntityTracker(this, victim, player, 200L); - } - remove(); - } - } - - private boolean grab() { - List entities = new ArrayList<>(); - for (int i = 1; i < distance; i++) { - Location location; - if (bloodbendingThroughBlocks) { - location = player.getTargetBlock(null, i).getLocation(); - } else { - location = GeneralMethods.getTargetedLocation(player, i, ElementalAbility.getTransparentMaterials()); - } - entities = GeneralMethods.getEntitiesAroundPoint(location, 1.7); - entities.remove(player); - - if (!entities.isEmpty() && !entities.contains(player)) { - break; - } - } - if (entities.isEmpty()) { - return false; - } - Entity e = entities.get(0); - if (e == null) { - return false; - } - if (!(e instanceof LivingEntity)) { - return false; - } - if (e instanceof ArmorStand) { - return false; - } - if (!undeadMobs && GeneralMethods.isUndead(e)) { - return false; - } - if ((e instanceof Player) && !canBeBloodbent((Player) e)) { - return false; - } - if (RegionProtection.isRegionProtected(player, e.getLocation(), this)) { - return false; - } - for (Bloodbending bb : getAbilities(Bloodbending.class)) { - if (bb.victim.getEntityId() == e.getEntityId()) { - return false; - } - } - - victim = (LivingEntity) e; - DamageHandler.damageEntity(victim, 0, this); - HorizontalVelocityTracker.remove(victim); - if (victim instanceof Creature) { - ((Creature) victim).setTarget(null); - } - if ((e instanceof Player) && BendingPlayer.getBendingPlayer((Player) e) != null) { - victimBPlayer = BendingPlayer.getBendingPlayer((Player) e); - } - return true; - } - - private boolean canBeBloodbent(Player player) { - if (Commands.invincible.contains(player.getName())) { - return false; - } - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - if (requireBound) { - if (bPlayer.getAbilities().containsValue("Bloodbending")) { - return false; - } - return !bPlayer.getAbilities().containsValue("BloodPuppet"); - } else { - if (bPlayer.canBind(getAbility("Bloodbending")) && bPlayer.canBloodbend()) { - return isDay(player.getWorld()) && !bPlayer.canBloodbendAtAnytime(); - } - } - return true; - } - - @Override - public void progress() { - if (!isEligible(player, false)) { - remove(); - return; - } - if (!grabbed) { - if (victim instanceof Player && victimBPlayer != null) { - victimBPlayer.blockChi(); - grabbed = true; - } - } - - if (!player.isSneaking()) { - remove(); - return; - } - if (!player.isOnline() || player.isDead()) { - remove(); - return; - } - if (System.currentTimeMillis() > time) { - remove(); - return; - } - if (victim.isDead()) { - remove(); - return; - } - if ((victim instanceof Player) && !((Player) victim).isOnline()) { - remove(); - return; - } - Location oldLocation = victim.getLocation(); - Location loc = GeneralMethods.getTargetedLocation(player, (int) player.getLocation().distance(oldLocation)); - double distance = loc.distance(oldLocation); - Vector v = GeneralMethods.getDirection(oldLocation, GeneralMethods.getTargetedLocation(player, 10)); - if (distance > 1.2D) { - victim.setVelocity(v.normalize().multiply(0.8D)); - } else { - victim.setVelocity(new Vector(0, 0, 0)); - } - victim.setFallDistance(0.0F); - if (victim instanceof Creature) { - ((Creature) victim).setTarget(null); - } - AirAbility.breakBreathbendingHold(victim); - } - - @Override - public void remove() { - if (player.isOnline()) { - bPlayer.addCooldown(this); - } - if (victim instanceof Player && victimBPlayer != null) { - victimBPlayer.unblockChi(); - } - super.remove(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "Bloodbending"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Water.Bloodbending.Description"); - } - - public boolean isNightOnly() { - return nightOnly; - } - - public void setNightOnly(boolean nightOnly) { - this.nightOnly = nightOnly; - } - - public boolean isFullMoonOnly() { - return fullMoonOnly; - } - - public void setFullMoonOnly(boolean fullMoonOnly) { - this.fullMoonOnly = fullMoonOnly; - } - - public boolean isUndeadMobs() { - return undeadMobs; - } - - public void setUndeadMobs(boolean undeadMobs) { - this.undeadMobs = undeadMobs; - } - - public boolean isBloodbendingThroughBlocks() { - return bloodbendingThroughBlocks; - } - - public void setBloodbendingThroughBlocks(boolean bloodbendingThroughBlocks) { - this.bloodbendingThroughBlocks = bloodbendingThroughBlocks; - } - - public boolean isRequireBound() { - return requireBound; - } - - public void setRequireBound(boolean requireBound) { - this.requireBound = requireBound; - } - - public int getDistance() { - return distance; - } - - public void setDistance(int distance) { - this.distance = distance; - } - - public long getHoldTime() { - return holdTime; - } - - public void setHoldTime(long holdTime) { - this.holdTime = holdTime; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getTime() { - return time; - } - - public void setTime(long time) { - this.time = time; - } - - public LivingEntity getVictim() { - return victim; - } - - public void setVictim(LivingEntity victim) { - this.victim = victim; - } - - public BendingPlayer getVictimBPlayer() { - return victimBPlayer; - } - - public void setVictimBPlayer(BendingPlayer victimBPlayer) { - this.victimBPlayer = victimBPlayer; - } - - public boolean isGrabbed() { - return grabbed; - } - - public void setGrabbed(boolean grabbed) { - this.grabbed = grabbed; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Water.Bloodbending.Enabled"); - } -} + private boolean nightOnly; + private boolean fullMoonOnly; + private boolean undeadMobs; + private boolean bloodbendingThroughBlocks; + private boolean requireBound; + private int distance; + @Attribute(Attribute.DURATION) + private long holdTime; + @Attribute(Attribute.COOLDOWN) + private long cooldown; + + private long time; + public LivingEntity victim; + private BendingPlayer victimBPlayer; + private boolean grabbed; + + public Bloodbending(Player player) { + super(player); + if (this.player == null || !isEligible(player, true)) { + return; + } + setFields(); + time = System.currentTimeMillis() + holdTime; + if (grab()) { + start(); + } + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + nightOnly = config.getBoolean("Abilities.Water.Bloodbending.NightOnly"); + fullMoonOnly = config.getBoolean("Abilities.Water.Bloodbending.FullMoonOnly"); + undeadMobs = config.getBoolean("Abilities.Water.Bloodbending.UndeadMobs"); + bloodbendingThroughBlocks = config.getBoolean("Abilities.Water.Bloodbending.IgnoreWalls"); + requireBound = config.getBoolean("Abilities.Water.Bloodbending.RequireBound"); + distance = config.getInt("Abilities.Water.Bloodbending.Distance"); + holdTime = config.getLong("Abilities.Water.Bloodbending.HoldTime"); + cooldown = config.getLong("Abilities.Water.Bloodbending.Cooldown"); + } + + public boolean isEligible(Player player, boolean hasAbility) { + if (!bPlayer.canBend(this) || !bPlayer.canBloodbend() || (hasAbility && hasAbility(player, Bloodbending.class))) { + return false; + } + if (nightOnly && !isNight(player.getWorld()) && !bPlayer.canBloodbendAtAnytime()) { + return false; + } + return !fullMoonOnly || isFullMoon(player.getWorld()) || bPlayer.canBloodbendAtAnytime(); + } + + public static void launch(Player player) { + if (hasAbility(player, Bloodbending.class)) { + getAbility(player, Bloodbending.class).launch(); + } + } + + private void launch() { + if (Arrays.asList(ElementalAbility.getTransparentMaterials()).contains(player.getEyeLocation().getBlock().getType())) { + Vector direction = GeneralMethods.getDirection(player.getEyeLocation(), GeneralMethods.getTargetedLocation(player, 20, ElementalAbility.getTransparentMaterials())).normalize().multiply(3); + if (!victim.isDead()) { + victim.setVelocity(direction); + + new HorizontalVelocityTracker(victim, player, 200L, this); + new ThrownEntityTracker(this, victim, player, 200L); + } + remove(); + } + } + + private boolean grab() { + List entities = new ArrayList<>(); + for (int i = 1; i < distance; i++) { + Location location; + if (bloodbendingThroughBlocks) { + location = player.getTargetBlock(null, i).getLocation(); + } else { + location = GeneralMethods.getTargetedLocation(player, i, ElementalAbility.getTransparentMaterials()); + } + entities = GeneralMethods.getEntitiesAroundPoint(location, 1.7); + entities.remove(player); + + if (!entities.isEmpty() && !entities.contains(player)) { + break; + } + } + if (entities.isEmpty()) { + return false; + } + Entity e = entities.get(0); + if (e == null) { + return false; + } + if (!(e instanceof LivingEntity)) { + return false; + } + if (e instanceof ArmorStand) { + return false; + } + if (!undeadMobs && GeneralMethods.isUndead(e)) { + return false; + } + if ((e instanceof Player) && !canBeBloodbent((Player) e)) { + return false; + } + if (RegionProtection.isRegionProtected(player, e.getLocation(), this)) { + return false; + } + for (Bloodbending bb : getAbilities(Bloodbending.class)) { + if (bb.victim.getEntityId() == e.getEntityId()) { + return false; + } + } + + victim = (LivingEntity) e; + DamageHandler.damageEntity(victim, 0, this); + HorizontalVelocityTracker.remove(victim); + if (victim instanceof Creature) { + ((Creature) victim).setTarget(null); + } + if ((e instanceof Player) && BendingPlayer.getBendingPlayer((Player) e) != null) { + victimBPlayer = BendingPlayer.getBendingPlayer((Player) e); + } + return true; + } + + private boolean canBeBloodbent(Player player) { + if (Commands.invincible.contains(player.getName())) { + return false; + } + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); + if (requireBound) { + if (bPlayer.getAbilities().containsValue("Bloodbending")) { + return false; + } + return !bPlayer.getAbilities().containsValue("BloodPuppet"); + } else { + if (bPlayer.canBind(getAbility("Bloodbending")) && bPlayer.canBloodbend()) { + return isDay(player.getWorld()) && !bPlayer.canBloodbendAtAnytime(); + } + } + return true; + } + + @Override + public void progress() { + if (!isEligible(player, false)) { + remove(); + return; + } + if (!grabbed) { + if (victim instanceof Player && victimBPlayer != null) { + victimBPlayer.blockChi(); + grabbed = true; + } + } + + if (!player.isSneaking()) { + remove(); + return; + } + if (!player.isOnline() || player.isDead()) { + remove(); + return; + } + if (System.currentTimeMillis() > time) { + remove(); + return; + } + if (victim.isDead()) { + remove(); + return; + } + if ((victim instanceof Player) && !((Player) victim).isOnline()) { + remove(); + return; + } + Location oldLocation = victim.getLocation(); + Location loc = GeneralMethods.getTargetedLocation(player, (int) player.getLocation().distance(oldLocation)); + double distance = loc.distance(oldLocation); + Vector v = GeneralMethods.getDirection(oldLocation, GeneralMethods.getTargetedLocation(player, 10)); + if (distance > 1.2D) { + victim.setVelocity(v.normalize().multiply(0.8D)); + } else { + victim.setVelocity(new Vector(0, 0, 0)); + } + victim.setFallDistance(0.0F); + if (victim instanceof Creature) { + ((Creature) victim).setTarget(null); + } + AirAbility.breakBreathbendingHold(victim); + } + + @Override + public void remove() { + if (player.isOnline()) { + bPlayer.addCooldown(this); + } + if (victim instanceof Player && victimBPlayer != null) { + victimBPlayer.unblockChi(); + } + super.remove(); + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "Bloodbending"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Water.Bloodbending.Description"); + } + + public boolean isNightOnly() { + return nightOnly; + } + + public void setNightOnly(boolean nightOnly) { + this.nightOnly = nightOnly; + } + + public boolean isFullMoonOnly() { + return fullMoonOnly; + } + + public void setFullMoonOnly(boolean fullMoonOnly) { + this.fullMoonOnly = fullMoonOnly; + } + + public boolean isUndeadMobs() { + return undeadMobs; + } + + public void setUndeadMobs(boolean undeadMobs) { + this.undeadMobs = undeadMobs; + } + + public boolean isBloodbendingThroughBlocks() { + return bloodbendingThroughBlocks; + } + + public void setBloodbendingThroughBlocks(boolean bloodbendingThroughBlocks) { + this.bloodbendingThroughBlocks = bloodbendingThroughBlocks; + } + + public boolean isRequireBound() { + return requireBound; + } + + public void setRequireBound(boolean requireBound) { + this.requireBound = requireBound; + } + + public int getDistance() { + return distance; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + public long getHoldTime() { + return holdTime; + } + + public void setHoldTime(long holdTime) { + this.holdTime = holdTime; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public LivingEntity getVictim() { + return victim; + } + + public void setVictim(LivingEntity victim) { + this.victim = victim; + } + + public BendingPlayer getVictimBPlayer() { + return victimBPlayer; + } + + public void setVictimBPlayer(BendingPlayer victimBPlayer) { + this.victimBPlayer = victimBPlayer; + } + + public boolean isGrabbed() { + return grabbed; + } + + public void setGrabbed(boolean grabbed) { + this.grabbed = grabbed; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Water.Bloodbending.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/Drain.java b/src/com/jedk1/jedcore/ability/waterbending/Drain.java index ea33485..7354bdc 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/Drain.java +++ b/src/com/jedk1/jedcore/ability/waterbending/Drain.java @@ -11,7 +11,6 @@ import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.waterbending.util.WaterReturn; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -24,582 +23,576 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; +import java.util.*; public class Drain extends WaterAbility implements AddonAbility { - private final List locations = new ArrayList<>(); - static final Set WATER_TEMPS = new HashSet<>(); - - //Savannas are 1.0 temp with 0 humidity. Deserts are 2.0 temp with 0 humidity. - private static float MAX_TEMP = 1.0F; - private static float MIN_HUMIDITY = 0.01F; - - private long regenDelay; - @Attribute(Attribute.DURATION) - private long duration; // 2000 - @Attribute(Attribute.COOLDOWN) - private long cooldown; // 2000 - private double absorbSpeed; // 0.1 - @Attribute(Attribute.RADIUS) - private int radius; // 6 - @Attribute("Chance") - private int chance; // 20 - private int absorbRate; // 6 - private int holdRange; // 2 - private boolean blastsEnabled; // true - private int maxBlasts; - private boolean keepSrc; // false - private boolean useRain; - private boolean usePlants; - - private double blastRange; // 20 - private double blastDamage; // 1.5 - private double blastSpeed; // 2 - - private boolean drainTemps; - - private long endTime; - private int absorbed = 0; - private int charge = 7; - private boolean noFill; - private int blasts; - private boolean hasCharge; - private final Material[] fillables = { Material.GLASS_BOTTLE, Material.BUCKET }; - - Random rand = new Random(); - - public Drain(Player player) { - super(player); - if (!bPlayer.canBend(this) || hasAbility(player, Drain.class)) { - return; - } - setFields(); - this.usePlants = bPlayer.canPlantbend(); - endTime = System.currentTimeMillis() + duration; - if (!canFill()) { - if (!blastsEnabled) - return; - noFill = true; - } - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - regenDelay = config.getLong("Abilities.Water.Drain.RegenDelay"); - duration = config.getLong("Abilities.Water.Drain.Duration"); - cooldown = config.getLong("Abilities.Water.Drain.Cooldown"); - absorbSpeed = config.getDouble("Abilities.Water.Drain.AbsorbSpeed"); - radius = config.getInt("Abilities.Water.Drain.Radius"); - chance = config.getInt("Abilities.Water.Drain.AbsorbChance"); - absorbRate = config.getInt("Abilities.Water.Drain.AbsorbRate"); - holdRange = config.getInt("Abilities.Water.Drain.HoldRange"); - blastsEnabled = config.getBoolean("Abilities.Water.Drain.BlastsEnabled"); - maxBlasts = config.getInt("Abilities.Water.Drain.MaxBlasts"); - keepSrc = config.getBoolean("Abilities.Water.Drain.KeepSource"); - blastRange = config.getDouble("Abilities.Water.Drain.BlastRange"); - blastDamage = config.getDouble("Abilities.Water.Drain.BlastDamage"); - blastSpeed = config.getDouble("Abilities.Water.Drain.BlastSpeed"); - useRain = config.getBoolean("Abilities.Water.Drain.AllowRainSource"); - drainTemps = config.getBoolean("Abilities.Water.Drain.DrainTempBlocks"); - - applyModifiers(); - } - - private void applyModifiers() { - if (isNight(player.getWorld())) { - cooldown -= ((long) getNightFactor(cooldown) - cooldown); - blastRange = getNightFactor(blastRange); - blastDamage = getNightFactor(blastDamage); - } - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - if (!bPlayer.canBendIgnoreCooldowns(this)) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (!noFill) { - if (!player.isSneaking()) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (!canFill()) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (System.currentTimeMillis() > endTime) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (absorbed >= absorbRate) { - fill(); - absorbed = 0; - } - checkForValidSource(); - } else { - if (blasts >= maxBlasts) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (player.isSneaking()) { - if (charge >= 2) { - checkForValidSource(); - } - if (absorbed >= absorbRate) { - hasCharge = true; - absorbed = 0; - if (charge >= 3) { - charge -= 2; - } - } - } else if (!hasCharge || !keepSrc) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (hasCharge) { - displayWaterSource(); - } - } - dragWater(); - } - - public static void fireBlast(Player player) { - if (hasAbility(player, Drain.class)) { - getAbility(player, Drain.class).fireBlast(); - } - } - - private void fireBlast() { - if (charge <= 1) { - hasCharge = false; - charge = 7; - blasts++; - new DrainBlast(player, blastRange, blastDamage, blastSpeed, holdRange); - } - } - - private void displayWaterSource() { - Location location = player.getEyeLocation().add(player.getLocation().getDirection().multiply(holdRange)); - Block block = location.getBlock(); - if (!GeneralMethods.isSolid(block) || isTransparent(block)) { - TempBlock tb = new TempBlock(block, Material.WATER.createBlockData(bd -> ((Levelled) bd).setLevel(charge)), 100L); - WATER_TEMPS.add(tb); - tb.setRevertTask(() -> WATER_TEMPS.remove(tb)); - } - } - - private boolean canFill() { - for (ItemStack items : player.getInventory()) { - if (items != null && Arrays.asList(fillables).contains(items.getType())) { - return true; - } - } - return false; - } - - private void fill() { - for (int x = 0; x < absorbed; x++) { - for (Material fillable : fillables) { - int slot = player.getInventory().first(fillable); - if (slot == -1){ - continue; - } - if (player.getInventory().getItem(slot).getAmount() > 1) { - player.getInventory().getItem(slot).setAmount(player.getInventory().getItem(slot).getAmount() - 1); - - ItemStack filled = getFilled(fillable); - HashMap cantfit = player.getInventory().addItem(filled); - for (int id : cantfit.keySet()) { - player.getWorld().dropItem(player.getEyeLocation(), cantfit.get(id)); - } - } else { - player.getInventory().setItem(slot, getFilled(fillable)); - } - break; - } - } - } - - private ItemStack getFilled(Material type) { - ItemStack filled = null; - if (type == Material.GLASS_BOTTLE) { - filled = WaterReturn.waterBottleItem(); - } else if (type == Material.BUCKET) { - filled = new ItemStack(Material.WATER_BUCKET, 1); - } - - return filled; - } - - private void checkForValidSource() { - List locs = GeneralMethods.getCircle(player.getLocation(), radius, radius, false, true, 0); - for (int i = 0; i < locs.size(); i++) { - Block block = locs.get(rand.nextInt(locs.size()-1)).getBlock(); - if (rand.nextInt(chance) == 0) { - Location pLoc = player.getLocation(); - World world = pLoc.getWorld(); - double temp = world.getTemperature(pLoc.getBlockX(), pLoc.getBlockY(), pLoc.getBlockZ()); - double humidity = world.getHumidity(pLoc.getBlockX(), pLoc.getBlockY(), pLoc.getBlockZ()); - if (block.getY() > world.getMinHeight() && block.getY() < world.getMaxHeight()) { - Location bLoc = block.getLocation(); - if (useRain && world.hasStorm() && !(temp >= MAX_TEMP || humidity <= MIN_HUMIDITY)) { - if (pLoc.getY() >= world.getHighestBlockAt(pLoc).getLocation().getY()) { - if (bLoc.getY() >= world.getHighestBlockAt(pLoc).getLocation().getY()) { - locations.add(bLoc.clone().add(.5, .5, .5)); - return; - } - } - } - if (usePlants && JCMethods.isSmallPlant(block) && !isObstructed(bLoc, player.getEyeLocation())) { - drainPlant(block); - } else if (usePlants && ElementalAbility.isPlant(block) && !isObstructed(bLoc, player.getEyeLocation())) { - locations.add(bLoc.clone().add(.5, .5, .5)); - new TempBlock(block, Material.AIR.createBlockData(), regenDelay); - } else if (isWater(block)) { - TempBlock tb = TempBlock.get(block); - if ((tb == null || (drainTemps && !WATER_TEMPS.contains(tb)))) { - drainWater(block); - } - } - } - } - } - } - - private boolean isObstructed(Location location1, Location location2) { - Vector loc1 = location1.toVector(); - Vector loc2 = location2.toVector(); - - Vector direction = loc2.subtract(loc1); - direction.normalize(); - - Location loc; - - double max = location1.distance(location2); - - for (double i = 1; i <= max; i++) { - loc = location1.clone().add(direction.clone().multiply(i)); - if (!isTransparent(loc.getBlock())) - return true; - } - - return false; - } - - private void drainPlant(Block block) { - if (JCMethods.isSmallPlant(block)) { - if (JCMethods.isSmallPlant(block.getRelative(BlockFace.DOWN))) { - if (JCMethods.isDoublePlant(block.getType())) { - block = block.getRelative(BlockFace.DOWN); - locations.add(block.getLocation().clone().add(.5, .5, .5)); - new TempBlock(block, Material.DEAD_BUSH.createBlockData(), regenDelay); - return; - } - block = block.getRelative(BlockFace.DOWN); - } - locations.add(block.getLocation().clone().add(.5, .5, .5)); - new TempBlock(block, Material.DEAD_BUSH.createBlockData(), regenDelay); - } - } - - private void drainWater(Block block) { - if (isTransparent(block.getRelative(BlockFace.UP)) && !isWater(block.getRelative(BlockFace.UP))) { - locations.add(block.getLocation().clone().add(.5, .5, .5)); - if (block.getBlockData() instanceof Waterlogged) { - new TempBlock(block, block.getType().createBlockData(bd -> ((Waterlogged) bd).setWaterlogged(false)), regenDelay); - } else { - TempBlock tb = new TempBlock(block, Material.WATER.createBlockData(bd -> ((Levelled) bd).setLevel(1)), regenDelay); - WATER_TEMPS.add(tb); - tb.setRevertTask(() -> WATER_TEMPS.remove(tb)); - } - } - } - - private void dragWater() { - List toRemove = new ArrayList<>(); - if (!locations.isEmpty()) { - for (Location l : locations) { - Location playerLoc = player.getLocation().add(0, 1, 0); - if (noFill) - playerLoc = player.getEyeLocation().add(player.getLocation().getDirection().multiply(holdRange)).subtract(0, .8, 0); - Vector dir = GeneralMethods.getDirection(l, playerLoc); - l = l.add(dir.multiply(absorbSpeed)); - ParticleEffect.WATER_SPLASH.display(l, 1, 0, 0, 0, 0); - GeneralMethods.displayColoredParticle("0099FF", l); - if (l.distance(playerLoc) < 1) { - toRemove.add(locations.indexOf(l)); - absorbed++; - } - } - } - if (!toRemove.isEmpty()) { - for (int i : toRemove) { - if (i < locations.size()) - locations.remove(i); - } - toRemove.clear(); - } - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "Drain"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Water.Drain.Description"); - } - - @Override - public List getLocations() { - return locations; - } - - public long getRegenDelay() { - return regenDelay; - } - - public void setRegenDelay(long regenDelay) { - this.regenDelay = regenDelay; - } - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public double getAbsorbSpeed() { - return absorbSpeed; - } - - public void setAbsorbSpeed(double absorbSpeed) { - this.absorbSpeed = absorbSpeed; - } - - public int getRadius() { - return radius; - } - - public void setRadius(int radius) { - this.radius = radius; - } - - public int getChance() { - return chance; - } - - public void setChance(int chance) { - this.chance = chance; - } - - public int getAbsorbRate() { - return absorbRate; - } - - public void setAbsorbRate(int absorbRate) { - this.absorbRate = absorbRate; - } - - public int getHoldRange() { - return holdRange; - } - - public void setHoldRange(int holdRange) { - this.holdRange = holdRange; - } - - public boolean isBlastsEnabled() { - return blastsEnabled; - } - - public void setBlastsEnabled(boolean blastsEnabled) { - this.blastsEnabled = blastsEnabled; - } - - public int getMaxBlasts() { - return maxBlasts; - } - - public void setMaxBlasts(int maxBlasts) { - this.maxBlasts = maxBlasts; - } - - public boolean isKeepSrc() { - return keepSrc; - } - - public void setKeepSrc(boolean keepSrc) { - this.keepSrc = keepSrc; - } + private final List locations = new ArrayList<>(); + static final Set WATER_TEMPS = new HashSet<>(); + + //Savannas are 1.0 temp with 0 humidity. Deserts are 2.0 temp with 0 humidity. + private static float MAX_TEMP = 1.0F; + private static float MIN_HUMIDITY = 0.01F; + + private long regenDelay; + @Attribute(Attribute.DURATION) + private long duration; // 2000 + @Attribute(Attribute.COOLDOWN) + private long cooldown; // 2000 + private double absorbSpeed; // 0.1 + @Attribute(Attribute.RADIUS) + private int radius; // 6 + @Attribute("Chance") + private int chance; // 20 + private int absorbRate; // 6 + private int holdRange; // 2 + private boolean blastsEnabled; // true + private int maxBlasts; + private boolean keepSrc; // false + private boolean useRain; + private boolean usePlants; + + private double blastRange; // 20 + private double blastDamage; // 1.5 + private double blastSpeed; // 2 + + private boolean drainTemps; + + private long endTime; + private int absorbed = 0; + private int charge = 7; + private boolean noFill; + private int blasts; + private boolean hasCharge; + private final Material[] fillables = { Material.GLASS_BOTTLE, Material.BUCKET }; + + Random rand = new Random(); + + public Drain(Player player) { + super(player); + if (!bPlayer.canBend(this) || hasAbility(player, Drain.class)) { + return; + } + setFields(); + this.usePlants = bPlayer.canPlantbend(); + endTime = System.currentTimeMillis() + duration; + if (!canFill()) { + if (!blastsEnabled) + return; + noFill = true; + } + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + regenDelay = config.getLong("Abilities.Water.Drain.RegenDelay"); + duration = config.getLong("Abilities.Water.Drain.Duration"); + cooldown = config.getLong("Abilities.Water.Drain.Cooldown"); + absorbSpeed = config.getDouble("Abilities.Water.Drain.AbsorbSpeed"); + radius = config.getInt("Abilities.Water.Drain.Radius"); + chance = config.getInt("Abilities.Water.Drain.AbsorbChance"); + absorbRate = config.getInt("Abilities.Water.Drain.AbsorbRate"); + holdRange = config.getInt("Abilities.Water.Drain.HoldRange"); + blastsEnabled = config.getBoolean("Abilities.Water.Drain.BlastsEnabled"); + maxBlasts = config.getInt("Abilities.Water.Drain.MaxBlasts"); + keepSrc = config.getBoolean("Abilities.Water.Drain.KeepSource"); + blastRange = config.getDouble("Abilities.Water.Drain.BlastRange"); + blastDamage = config.getDouble("Abilities.Water.Drain.BlastDamage"); + blastSpeed = config.getDouble("Abilities.Water.Drain.BlastSpeed"); + useRain = config.getBoolean("Abilities.Water.Drain.AllowRainSource"); + drainTemps = config.getBoolean("Abilities.Water.Drain.DrainTempBlocks"); + + applyModifiers(); + } + + private void applyModifiers() { + if (isNight(player.getWorld())) { + cooldown -= ((long) getNightFactor(cooldown) - cooldown); + blastRange = getNightFactor(blastRange); + blastDamage = getNightFactor(blastDamage); + } + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + if (!bPlayer.canBendIgnoreCooldowns(this)) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (!noFill) { + if (!player.isSneaking()) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (!canFill()) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (System.currentTimeMillis() > endTime) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (absorbed >= absorbRate) { + fill(); + absorbed = 0; + } + checkForValidSource(); + } else { + if (blasts >= maxBlasts) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (player.isSneaking()) { + if (charge >= 2) { + checkForValidSource(); + } + if (absorbed >= absorbRate) { + hasCharge = true; + absorbed = 0; + if (charge >= 3) { + charge -= 2; + } + } + } else if (!hasCharge || !keepSrc) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (hasCharge) { + displayWaterSource(); + } + } + dragWater(); + } + + public static void fireBlast(Player player) { + if (hasAbility(player, Drain.class)) { + getAbility(player, Drain.class).fireBlast(); + } + } + + private void fireBlast() { + if (charge <= 1) { + hasCharge = false; + charge = 7; + blasts++; + new DrainBlast(player, blastRange, blastDamage, blastSpeed, holdRange); + } + } + + private void displayWaterSource() { + Location location = player.getEyeLocation().add(player.getLocation().getDirection().multiply(holdRange)); + Block block = location.getBlock(); + if (!GeneralMethods.isSolid(block) || isTransparent(block)) { + TempBlock tb = new TempBlock(block, Material.WATER.createBlockData(bd -> ((Levelled) bd).setLevel(charge)), 100L); + WATER_TEMPS.add(tb); + tb.setRevertTask(() -> WATER_TEMPS.remove(tb)); + } + } + + private boolean canFill() { + for (ItemStack items : player.getInventory()) { + if (items != null && Arrays.asList(fillables).contains(items.getType())) { + return true; + } + } + return false; + } + + private void fill() { + for (int x = 0; x < absorbed; x++) { + for (Material fillable : fillables) { + int slot = player.getInventory().first(fillable); + if (slot == -1){ + continue; + } + if (player.getInventory().getItem(slot).getAmount() > 1) { + player.getInventory().getItem(slot).setAmount(player.getInventory().getItem(slot).getAmount() - 1); + + ItemStack filled = getFilled(fillable); + HashMap cantfit = player.getInventory().addItem(filled); + for (int id : cantfit.keySet()) { + player.getWorld().dropItem(player.getEyeLocation(), cantfit.get(id)); + } + } else { + player.getInventory().setItem(slot, getFilled(fillable)); + } + break; + } + } + } + + private ItemStack getFilled(Material type) { + ItemStack filled = null; + if (type == Material.GLASS_BOTTLE) { + filled = WaterReturn.waterBottleItem(); + } else if (type == Material.BUCKET) { + filled = new ItemStack(Material.WATER_BUCKET, 1); + } + + return filled; + } + + private void checkForValidSource() { + List locs = GeneralMethods.getCircle(player.getLocation(), radius, radius, false, true, 0); + for (int i = 0; i < locs.size(); i++) { + Block block = locs.get(rand.nextInt(locs.size()-1)).getBlock(); + if (rand.nextInt(chance) == 0) { + Location pLoc = player.getLocation(); + World world = pLoc.getWorld(); + double temp = world.getTemperature(pLoc.getBlockX(), pLoc.getBlockY(), pLoc.getBlockZ()); + double humidity = world.getHumidity(pLoc.getBlockX(), pLoc.getBlockY(), pLoc.getBlockZ()); + if (block.getY() > world.getMinHeight() && block.getY() < world.getMaxHeight()) { + Location bLoc = block.getLocation(); + if (useRain && world.hasStorm() && !(temp >= MAX_TEMP || humidity <= MIN_HUMIDITY)) { + if (pLoc.getY() >= world.getHighestBlockAt(pLoc).getLocation().getY()) { + if (bLoc.getY() >= world.getHighestBlockAt(pLoc).getLocation().getY()) { + locations.add(bLoc.clone().add(.5, .5, .5)); + return; + } + } + } + if (usePlants && JCMethods.isSmallPlant(block) && !isObstructed(bLoc, player.getEyeLocation())) { + drainPlant(block); + } else if (usePlants && ElementalAbility.isPlant(block) && !isObstructed(bLoc, player.getEyeLocation())) { + locations.add(bLoc.clone().add(.5, .5, .5)); + new TempBlock(block, Material.AIR.createBlockData(), regenDelay); + } else if (isWater(block)) { + TempBlock tb = TempBlock.get(block); + if ((tb == null || (drainTemps && !WATER_TEMPS.contains(tb)))) { + drainWater(block); + } + } + } + } + } + } + + private boolean isObstructed(Location location1, Location location2) { + Vector loc1 = location1.toVector(); + Vector loc2 = location2.toVector(); + + Vector direction = loc2.subtract(loc1); + direction.normalize(); + + Location loc; + + double max = location1.distance(location2); + + for (double i = 1; i <= max; i++) { + loc = location1.clone().add(direction.clone().multiply(i)); + if (!isTransparent(loc.getBlock())) + return true; + } + + return false; + } + + private void drainPlant(Block block) { + if (JCMethods.isSmallPlant(block)) { + if (JCMethods.isSmallPlant(block.getRelative(BlockFace.DOWN))) { + if (JCMethods.isDoublePlant(block.getType())) { + block = block.getRelative(BlockFace.DOWN); + locations.add(block.getLocation().clone().add(.5, .5, .5)); + new TempBlock(block, Material.DEAD_BUSH.createBlockData(), regenDelay); + return; + } + block = block.getRelative(BlockFace.DOWN); + } + locations.add(block.getLocation().clone().add(.5, .5, .5)); + new TempBlock(block, Material.DEAD_BUSH.createBlockData(), regenDelay); + } + } + + private void drainWater(Block block) { + if (isTransparent(block.getRelative(BlockFace.UP)) && !isWater(block.getRelative(BlockFace.UP))) { + locations.add(block.getLocation().clone().add(.5, .5, .5)); + if (block.getBlockData() instanceof Waterlogged) { + new TempBlock(block, block.getType().createBlockData(bd -> ((Waterlogged) bd).setWaterlogged(false)), regenDelay); + } else { + TempBlock tb = new TempBlock(block, Material.WATER.createBlockData(bd -> ((Levelled) bd).setLevel(1)), regenDelay); + WATER_TEMPS.add(tb); + tb.setRevertTask(() -> WATER_TEMPS.remove(tb)); + } + } + } + + private void dragWater() { + List toRemove = new ArrayList<>(); + if (!locations.isEmpty()) { + for (Location l : locations) { + Location playerLoc = player.getLocation().add(0, 1, 0); + if (noFill) + playerLoc = player.getEyeLocation().add(player.getLocation().getDirection().multiply(holdRange)).subtract(0, .8, 0); + Vector dir = GeneralMethods.getDirection(l, playerLoc); + l = l.add(dir.multiply(absorbSpeed)); + ParticleEffect.WATER_SPLASH.display(l, 1, 0, 0, 0, 0); + GeneralMethods.displayColoredParticle("0099FF", l); + if (l.distance(playerLoc) < 1) { + toRemove.add(locations.indexOf(l)); + absorbed++; + } + } + } + if (!toRemove.isEmpty()) { + for (int i : toRemove) { + if (i < locations.size()) + locations.remove(i); + } + toRemove.clear(); + } + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "Drain"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Water.Drain.Description"); + } + + @Override + public List getLocations() { + return locations; + } + + public long getRegenDelay() { + return regenDelay; + } + + public void setRegenDelay(long regenDelay) { + this.regenDelay = regenDelay; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public double getAbsorbSpeed() { + return absorbSpeed; + } + + public void setAbsorbSpeed(double absorbSpeed) { + this.absorbSpeed = absorbSpeed; + } + + public int getRadius() { + return radius; + } + + public void setRadius(int radius) { + this.radius = radius; + } + + public int getChance() { + return chance; + } + + public void setChance(int chance) { + this.chance = chance; + } + + public int getAbsorbRate() { + return absorbRate; + } + + public void setAbsorbRate(int absorbRate) { + this.absorbRate = absorbRate; + } + + public int getHoldRange() { + return holdRange; + } + + public void setHoldRange(int holdRange) { + this.holdRange = holdRange; + } + + public boolean isBlastsEnabled() { + return blastsEnabled; + } + + public void setBlastsEnabled(boolean blastsEnabled) { + this.blastsEnabled = blastsEnabled; + } + + public int getMaxBlasts() { + return maxBlasts; + } + + public void setMaxBlasts(int maxBlasts) { + this.maxBlasts = maxBlasts; + } + + public boolean isKeepSrc() { + return keepSrc; + } + + public void setKeepSrc(boolean keepSrc) { + this.keepSrc = keepSrc; + } - public boolean isUseRain() { - return useRain; - } + public boolean isUseRain() { + return useRain; + } - public void setUseRain(boolean useRain) { - this.useRain = useRain; - } + public void setUseRain(boolean useRain) { + this.useRain = useRain; + } - public boolean isUsePlants() { - return usePlants; - } - - public void setUsePlants(boolean usePlants) { - this.usePlants = usePlants; - } + public boolean isUsePlants() { + return usePlants; + } + + public void setUsePlants(boolean usePlants) { + this.usePlants = usePlants; + } - public double getBlastRange() { - return blastRange; - } + public double getBlastRange() { + return blastRange; + } - public void setBlastRange(double blastRange) { - this.blastRange = blastRange; - } + public void setBlastRange(double blastRange) { + this.blastRange = blastRange; + } - public double getBlastDamage() { - return blastDamage; - } + public double getBlastDamage() { + return blastDamage; + } - public void setBlastDamage(double blastDamage) { - this.blastDamage = blastDamage; - } + public void setBlastDamage(double blastDamage) { + this.blastDamage = blastDamage; + } - public double getBlastSpeed() { - return blastSpeed; - } + public double getBlastSpeed() { + return blastSpeed; + } - public void setBlastSpeed(double blastSpeed) { - this.blastSpeed = blastSpeed; - } + public void setBlastSpeed(double blastSpeed) { + this.blastSpeed = blastSpeed; + } - public boolean isDrainTemps() { - return drainTemps; - } + public boolean isDrainTemps() { + return drainTemps; + } - public void setDrainTemps(boolean drainTemps) { - this.drainTemps = drainTemps; - } + public void setDrainTemps(boolean drainTemps) { + this.drainTemps = drainTemps; + } - public long getEndTime() { - return endTime; - } + public long getEndTime() { + return endTime; + } - public void setEndTime(long endTime) { - this.endTime = endTime; - } + public void setEndTime(long endTime) { + this.endTime = endTime; + } - public int getAbsorbed() { - return absorbed; - } + public int getAbsorbed() { + return absorbed; + } - public void setAbsorbed(int absorbed) { - this.absorbed = absorbed; - } + public void setAbsorbed(int absorbed) { + this.absorbed = absorbed; + } - public int getCharge() { - return charge; - } + public int getCharge() { + return charge; + } - public void setCharge(int charge) { - this.charge = charge; - } + public void setCharge(int charge) { + this.charge = charge; + } - public boolean isNoFill() { - return noFill; - } + public boolean isNoFill() { + return noFill; + } - public void setNoFill(boolean noFill) { - this.noFill = noFill; - } + public void setNoFill(boolean noFill) { + this.noFill = noFill; + } - public int getBlasts() { - return blasts; - } + public int getBlasts() { + return blasts; + } - public void setBlasts(int blasts) { - this.blasts = blasts; - } + public void setBlasts(int blasts) { + this.blasts = blasts; + } - public boolean isHasCharge() { - return hasCharge; - } + public boolean isHasCharge() { + return hasCharge; + } - public void setHasCharge(boolean hasCharge) { - this.hasCharge = hasCharge; - } + public void setHasCharge(boolean hasCharge) { + this.hasCharge = hasCharge; + } - public Material[] getFillables() { - return fillables; - } + public Material[] getFillables() { + return fillables; + } - @Override - public void load() {} + @Override + public void load() {} - @Override - public void stop() {} + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Water.Drain.Enabled"); - } -} + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Water.Drain.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/DrainBlast.java b/src/com/jedk1/jedcore/ability/waterbending/DrainBlast.java index 7656c6f..1912d14 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/DrainBlast.java +++ b/src/com/jedk1/jedcore/ability/waterbending/DrainBlast.java @@ -8,7 +8,6 @@ import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.TempBlock; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.Levelled; diff --git a/src/com/jedk1/jedcore/ability/waterbending/FrostBreath.java b/src/com/jedk1/jedcore/ability/waterbending/FrostBreath.java index 9a2ab0f..3ca79fa 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/FrostBreath.java +++ b/src/com/jedk1/jedcore/ability/waterbending/FrostBreath.java @@ -1,13 +1,16 @@ package com.jedk1.jedcore.ability.waterbending; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import com.jedk1.jedcore.JCMethods; +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.IceAbility; import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.region.RegionProtection; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.waterbending.ice.PhaseChange; import org.bukkit.Location; import org.bukkit.Material; @@ -18,423 +21,419 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.IceAbility; -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.Arrays; +import java.util.List; public class FrostBreath extends IceAbility implements AddonAbility { - private static final List INVALID_MATERIALS = new ArrayList(){{ - addAll(Arrays.asList( - Material.ICE, - Material.LAVA, - Material.AIR, - Material.VOID_AIR, - Material.CAVE_AIR)); - if (GeneralMethods.getMCVersion() >= 1170) { - add(Material.getMaterial("LIGHT")); - } - }}; - - //Savannas are 1.0 temp with 0 humidity. Deserts are 2.0 temp with 0 humidity. - private static float MAX_TEMP = 1.0F; - private static float MIN_HUMIDITY = 0.01F; - - public Config config; - - private State state; - private final List frozenBlocks = new ArrayList<>(); - - public FrostBreath(Player player) { - super(player); - - if (!bPlayer.canBend(this) || !bPlayer.canIcebend()) { - return; - } - - this.config = new Config(player); - this.state = new BeamState(); - - double temp = player.getLocation().getWorld().getTemperature(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()); - double humidity = player.getLocation().getWorld().getHumidity(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()); - - if (config.restrictBiomes && (temp >= MAX_TEMP || humidity <= MIN_HUMIDITY)) { - return; - } - - start(); - } - - @Override - public void progress() { - if (!state.update()) { - remove(); - } - - long time = System.currentTimeMillis(); - - frozenBlocks.removeIf(frozen -> { - if (time >= frozen.endTime) { - removeFrozenBlock(frozen.tempBlock); - frozen.tempBlock.revertBlock(); - return true; - } - - return false; - }); - } - - @Override - public void remove() { - super.remove(); - - frozenBlocks.forEach(fb -> { - removeFrozenBlock(fb.tempBlock); - fb.tempBlock.revertBlock(); - }); - frozenBlocks.clear(); - } - - @Override - public long getCooldown() { - return config.cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "FrostBreath"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Water.FrostBreath.Description"); - } - - public static List getInvalidMaterials() { - return INVALID_MATERIALS; - } - - public State getState() { - return state; - } - - public void setState(State state) { - this.state = state; - } - - public List getFrozenBlocks() { - return frozenBlocks; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Water.FrostBreath.Enabled"); - } - - private void addFrozenBlock(TempBlock tempBlock) { - PhaseChange.getFrozenBlocksMap().put(tempBlock, player); - } - - private void removeFrozenBlock(TempBlock tempBlock) { - PhaseChange.getFrozenBlocksMap().remove(tempBlock); - } - - private interface State { - boolean update(); - } - - private class BeamState implements State { - @Override - public boolean update() { - if (player == null || !player.isOnline()) { - return transition(); - } - - if (!bPlayer.canBendIgnoreCooldowns(FrostBreath.this)) { - return transition(); - } - - if (!player.isSneaking() || player.isDead()) { - return transition(); - } - - if (System.currentTimeMillis() >= getStartTime() + config.duration) { - return transition(); - } - - createBeam(); - - return true; - } - - private boolean transition() { - state = new SnowMeltingState(); - - return true; - } - - private boolean isLocationSafe(Location loc) { - Block block = loc.getBlock(); - - if (RegionProtection.isRegionProtected(player, loc, FrostBreath.this)) { - return false; - } - - return isTransparent(block); - } - - private boolean isFreezable(Location location, Entity entity) { - if (RegionProtection.isRegionProtected(FrostBreath.this, location)) { - return false; - } - - if (entity instanceof Player && Commands.invincible.contains(entity.getName())) { - return false; - } - - return !location.getBlock().getType().isSolid(); - } - - private void createBeam() { - Location loc = player.getEyeLocation(); - Vector dir = player.getLocation().getDirection(); - double step = 1; - double size = 0; - double offset = 0; - double damageRegion = 1.5; - - for (double i = 0; i < config.range; i += step) { - loc = loc.add(dir.clone().multiply(step)); - size += 0.005; - offset += 0.3; - damageRegion += 0.01; - - if (!isLocationSafe(loc)) - return; - - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(loc, damageRegion)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) { - for (Location cageLocation : createCage(entity.getLocation())) { - if (isFreezable(cageLocation, entity)) { - Block block = cageLocation.getBlock(); - - updateFrozenBlock(block, Material.ICE, config.freezeDuration); - } - } - - if (config.slowEnabled) { - ((LivingEntity) entity).addPotionEffect(JedCore.plugin.getPotionEffectAdapter().getSlownessEffect((int) config.slowDuration, 5)); - } - - if (config.damageEnabled) { - if (entity instanceof Player) { - DamageHandler.damageEntity(entity, config.playerDamage, FrostBreath.this); - } else { - DamageHandler.damageEntity(entity, config.mobDamage, FrostBreath.this); - } - } - } - } - - if (config.snowEnabled) { - freezeGround(loc); - } - - ParticleEffect.SNOW_SHOVEL.display(loc, config.particles, Math.random(), Math.random(), Math.random(), size); - - JCMethods.displayColoredParticles("#DCDCDC", loc, 1, Math.random(), Math.random(), Math.random(), 0.003f); - JCMethods.displayColoredParticles("#9696FF", loc, 1, Math.random(), Math.random(), Math.random(), 0.0035f); - } - } - - private Location getOffsetLocation(Location loc, double offset) { - return loc.clone().add((float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset)); - } - - private void freezeGround(Location loc) { - for (Location l : GeneralMethods.getCircle(loc, 2, 2, false, true, 0)) { - if (!RegionProtection.isRegionProtected(player, l, FrostBreath.this)) { - Block block = l.getBlock(); - - if (isWater(l.getBlock())) { - updateFrozenBlock(block, Material.ICE, config.frozenWaterDuration); - } else if (isTransparent(l.getBlock()) && l.clone().add(0, -1, 0).getBlock().getType().isSolid() && !INVALID_MATERIALS.contains(l.clone().add(0, -1, 0).getBlock().getType())) { - if (config.bendSnow) { - updateFrozenBlock(block, Material.SNOW, config.snowDuration); - } else { - TempBlock current = TempBlock.get(block); - - // Refresh any existing TempBlock so the timer resets. - if (current != null) { - current.revertBlock(); - } - - TempBlock tempBlock = new TempBlock(block, Material.SNOW.createBlockData()); - tempBlock.setRevertTime(config.snowDuration); - } - } - } - } - } - - private void updateFrozenBlock(Block block, Material type, long duration) { - // Store the TempBlock as a FrozenBlock block so it can be reverted later. - for (FrozenBlock fb : frozenBlocks) { - if (fb.tempBlock.getBlock().equals(block)) { - if (fb.tempBlock.getBlockData().getMaterial() != type) { - // Completely overwrite this FrozenBlock if the new type doesn't match the old one. - removeFrozenBlock(fb.tempBlock); - fb.tempBlock.revertBlock(); - frozenBlocks.remove(fb); - break; - } - - fb.endTime = System.currentTimeMillis() + duration; - return; - } - } - - TempBlock tempBlock = new TempBlock(block, type.createBlockData()); - - frozenBlocks.add(new FrozenBlock(tempBlock, System.currentTimeMillis() + duration)); - - // Add the TempBlock to a ProjectKorra block list so it can be used as a water source. - // I don't believe there exists a way to make a TempBlock water bendable right now, so this - // is a hack to make it work. - addFrozenBlock(tempBlock); - } - - private List createCage(Location centerBlock) { - List selectedBlocks = new ArrayList<>(); - - int bX = centerBlock.getBlockX(); - int bY = centerBlock.getBlockY(); - int bZ = centerBlock.getBlockZ(); - - for (int x = bX - 1; x <= bX + 1; x++) { - for (int y = bY - 1; y <= bY + 1; y++) { - Location l = new Location(centerBlock.getWorld(), x, y, bZ); - selectedBlocks.add(l); - } - } - - for (int y = bY - 1; y <= bY + 2; y++) { - Location l = new Location(centerBlock.getWorld(), bX, y, bZ); - selectedBlocks.add(l); - } - - for (int z = bZ - 1; z <= bZ + 1; z++) { - for (int y = bY - 1; y <= bY + 1; y++) { - Location l = new Location(centerBlock.getWorld(), bX, y, z); - selectedBlocks.add(l); - } - } - - for (int x = bX - 1; x <= bX + 1; x++) { - for (int z = bZ - 1; z <= bZ + 1; z++) { - Location l = new Location(centerBlock.getWorld(), x, bY, z); - selectedBlocks.add(l); - } - } - - return selectedBlocks; - } - } - - // Wait for the frozen blocks to melt and remove it from bendable water list. - private class SnowMeltingState implements State { - SnowMeltingState() { - bPlayer.addCooldown(FrostBreath.this); - } - - @Override - public boolean update() { - return !frozenBlocks.isEmpty(); - } - } - - private static class FrozenBlock { - TempBlock tempBlock; - long endTime; - - FrozenBlock(TempBlock tempBlock, long endTime) { - this.tempBlock = tempBlock; - this.endTime = endTime; - } - } - - public static class Config { - long cooldown; - long duration; - int particles; - int freezeDuration; - int snowDuration; - int frozenWaterDuration; - int range; - boolean snowEnabled; - boolean bendSnow; - boolean damageEnabled; - double playerDamage; - double mobDamage; - boolean slowEnabled; - long slowDuration; - boolean restrictBiomes; - - Config(Player player) { - ConfigurationSection config = JedCoreConfig.getConfig(player); - - cooldown = config.getLong("Abilities.Water.FrostBreath.Cooldown"); - duration = config.getLong("Abilities.Water.FrostBreath.Duration"); - particles = config.getInt("Abilities.Water.FrostBreath.Particles"); - freezeDuration = config.getInt("Abilities.Water.FrostBreath.FrostDuration"); - snowDuration = config.getInt("Abilities.Water.FrostBreath.SnowDuration"); - frozenWaterDuration = config.getInt("Abilities.Water.FrostBreath.FrozenWaterDuration"); - range = config.getInt("Abilities.Water.FrostBreath.Range"); - snowEnabled = config.getBoolean("Abilities.Water.FrostBreath.Snow"); - bendSnow = config.getBoolean("Abilities.Water.FrostBreath.BendableSnow"); - damageEnabled = config.getBoolean("Abilities.Water.FrostBreath.Damage.Enabled"); - playerDamage = config.getDouble("Abilities.Water.FrostBreath.Damage.Player"); - mobDamage = config.getDouble("Abilities.Water.FrostBreath.Damage.Mob"); - slowEnabled = config.getBoolean("Abilities.Water.FrostBreath.Slow.Enabled"); - slowDuration = config.getLong("Abilities.Water.FrostBreath.Slow.Duration"); - restrictBiomes = config.getBoolean("Abilities.Water.FrostBreath.RestrictBiomes"); - } - } -} + private static final List INVALID_MATERIALS = new ArrayList(){{ + addAll(Arrays.asList( + Material.ICE, + Material.LAVA, + Material.AIR, + Material.VOID_AIR, + Material.CAVE_AIR)); + if (GeneralMethods.getMCVersion() >= 1170) { + add(Material.getMaterial("LIGHT")); + } + }}; + + //Savannas are 1.0 temp with 0 humidity. Deserts are 2.0 temp with 0 humidity. + private static float MAX_TEMP = 1.0F; + private static float MIN_HUMIDITY = 0.01F; + + public Config config; + + private State state; + private final List frozenBlocks = new ArrayList<>(); + + public FrostBreath(Player player) { + super(player); + + if (!bPlayer.canBend(this) || !bPlayer.canIcebend()) { + return; + } + + this.config = new Config(player); + this.state = new BeamState(); + + double temp = player.getLocation().getWorld().getTemperature(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()); + double humidity = player.getLocation().getWorld().getHumidity(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()); + + if (config.restrictBiomes && (temp >= MAX_TEMP || humidity <= MIN_HUMIDITY)) { + return; + } + + start(); + } + + @Override + public void progress() { + if (!state.update()) { + remove(); + } + + long time = System.currentTimeMillis(); + + frozenBlocks.removeIf(frozen -> { + if (time >= frozen.endTime) { + removeFrozenBlock(frozen.tempBlock); + frozen.tempBlock.revertBlock(); + return true; + } + + return false; + }); + } + + @Override + public void remove() { + super.remove(); + + frozenBlocks.forEach(fb -> { + removeFrozenBlock(fb.tempBlock); + fb.tempBlock.revertBlock(); + }); + frozenBlocks.clear(); + } + + @Override + public long getCooldown() { + return config.cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "FrostBreath"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Water.FrostBreath.Description"); + } + + public static List getInvalidMaterials() { + return INVALID_MATERIALS; + } + + public State getState() { + return state; + } + + public void setState(State state) { + this.state = state; + } + + public List getFrozenBlocks() { + return frozenBlocks; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Water.FrostBreath.Enabled"); + } + + private void addFrozenBlock(TempBlock tempBlock) { + PhaseChange.getFrozenBlocksMap().put(tempBlock, player); + } + + private void removeFrozenBlock(TempBlock tempBlock) { + PhaseChange.getFrozenBlocksMap().remove(tempBlock); + } + + private interface State { + boolean update(); + } + + private class BeamState implements State { + @Override + public boolean update() { + if (player == null || !player.isOnline()) { + return transition(); + } + + if (!bPlayer.canBendIgnoreCooldowns(FrostBreath.this)) { + return transition(); + } + + if (!player.isSneaking() || player.isDead()) { + return transition(); + } + + if (System.currentTimeMillis() >= getStartTime() + config.duration) { + return transition(); + } + + createBeam(); + + return true; + } + + private boolean transition() { + state = new SnowMeltingState(); + + return true; + } + + private boolean isLocationSafe(Location loc) { + Block block = loc.getBlock(); + + if (RegionProtection.isRegionProtected(player, loc, FrostBreath.this)) { + return false; + } + + return isTransparent(block); + } + + private boolean isFreezable(Location location, Entity entity) { + if (RegionProtection.isRegionProtected(FrostBreath.this, location)) { + return false; + } + + if (entity instanceof Player && Commands.invincible.contains(entity.getName())) { + return false; + } + + return !location.getBlock().getType().isSolid(); + } + + private void createBeam() { + Location loc = player.getEyeLocation(); + Vector dir = player.getLocation().getDirection(); + double step = 1; + double size = 0; + double offset = 0; + double damageRegion = 1.5; + + for (double i = 0; i < config.range; i += step) { + loc = loc.add(dir.clone().multiply(step)); + size += 0.005; + offset += 0.3; + damageRegion += 0.01; + + if (!isLocationSafe(loc)) + return; + + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(loc, damageRegion)) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) { + for (Location cageLocation : createCage(entity.getLocation())) { + if (isFreezable(cageLocation, entity)) { + Block block = cageLocation.getBlock(); + + updateFrozenBlock(block, Material.ICE, config.freezeDuration); + } + } + + if (config.slowEnabled) { + ((LivingEntity) entity).addPotionEffect(JedCore.plugin.getPotionEffectAdapter().getSlownessEffect((int) config.slowDuration, 5)); + } + + if (config.damageEnabled) { + if (entity instanceof Player) { + DamageHandler.damageEntity(entity, config.playerDamage, FrostBreath.this); + } else { + DamageHandler.damageEntity(entity, config.mobDamage, FrostBreath.this); + } + } + } + } + + if (config.snowEnabled) { + freezeGround(loc); + } + + ParticleEffect.SNOW_SHOVEL.display(loc, config.particles, Math.random(), Math.random(), Math.random(), size); + + JCMethods.displayColoredParticles("#DCDCDC", loc, 1, Math.random(), Math.random(), Math.random(), 0.003f); + JCMethods.displayColoredParticles("#9696FF", loc, 1, Math.random(), Math.random(), Math.random(), 0.0035f); + } + } + + private Location getOffsetLocation(Location loc, double offset) { + return loc.clone().add((float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset), (float) ((Math.random() - 0.5) * offset)); + } + + private void freezeGround(Location loc) { + for (Location l : GeneralMethods.getCircle(loc, 2, 2, false, true, 0)) { + if (!RegionProtection.isRegionProtected(player, l, FrostBreath.this)) { + Block block = l.getBlock(); + + if (isWater(l.getBlock())) { + updateFrozenBlock(block, Material.ICE, config.frozenWaterDuration); + } else if (isTransparent(l.getBlock()) && l.clone().add(0, -1, 0).getBlock().getType().isSolid() && !INVALID_MATERIALS.contains(l.clone().add(0, -1, 0).getBlock().getType())) { + if (config.bendSnow) { + updateFrozenBlock(block, Material.SNOW, config.snowDuration); + } else { + TempBlock current = TempBlock.get(block); + + // Refresh any existing TempBlock so the timer resets. + if (current != null) { + current.revertBlock(); + } + + TempBlock tempBlock = new TempBlock(block, Material.SNOW.createBlockData()); + tempBlock.setRevertTime(config.snowDuration); + } + } + } + } + } + + private void updateFrozenBlock(Block block, Material type, long duration) { + // Store the TempBlock as a FrozenBlock block so it can be reverted later. + for (FrozenBlock fb : frozenBlocks) { + if (fb.tempBlock.getBlock().equals(block)) { + if (fb.tempBlock.getBlockData().getMaterial() != type) { + // Completely overwrite this FrozenBlock if the new type doesn't match the old one. + removeFrozenBlock(fb.tempBlock); + fb.tempBlock.revertBlock(); + frozenBlocks.remove(fb); + break; + } + + fb.endTime = System.currentTimeMillis() + duration; + return; + } + } + + TempBlock tempBlock = new TempBlock(block, type.createBlockData()); + + frozenBlocks.add(new FrozenBlock(tempBlock, System.currentTimeMillis() + duration)); + + // Add the TempBlock to a ProjectKorra block list so it can be used as a water source. + // I don't believe there exists a way to make a TempBlock water bendable right now, so this + // is a hack to make it work. + addFrozenBlock(tempBlock); + } + + private List createCage(Location centerBlock) { + List selectedBlocks = new ArrayList<>(); + + int bX = centerBlock.getBlockX(); + int bY = centerBlock.getBlockY(); + int bZ = centerBlock.getBlockZ(); + + for (int x = bX - 1; x <= bX + 1; x++) { + for (int y = bY - 1; y <= bY + 1; y++) { + Location l = new Location(centerBlock.getWorld(), x, y, bZ); + selectedBlocks.add(l); + } + } + + for (int y = bY - 1; y <= bY + 2; y++) { + Location l = new Location(centerBlock.getWorld(), bX, y, bZ); + selectedBlocks.add(l); + } + + for (int z = bZ - 1; z <= bZ + 1; z++) { + for (int y = bY - 1; y <= bY + 1; y++) { + Location l = new Location(centerBlock.getWorld(), bX, y, z); + selectedBlocks.add(l); + } + } + + for (int x = bX - 1; x <= bX + 1; x++) { + for (int z = bZ - 1; z <= bZ + 1; z++) { + Location l = new Location(centerBlock.getWorld(), x, bY, z); + selectedBlocks.add(l); + } + } + + return selectedBlocks; + } + } + + // Wait for the frozen blocks to melt and remove it from bendable water list. + private class SnowMeltingState implements State { + SnowMeltingState() { + bPlayer.addCooldown(FrostBreath.this); + } + + @Override + public boolean update() { + return !frozenBlocks.isEmpty(); + } + } + + private static class FrozenBlock { + TempBlock tempBlock; + long endTime; + + FrozenBlock(TempBlock tempBlock, long endTime) { + this.tempBlock = tempBlock; + this.endTime = endTime; + } + } + + public static class Config { + long cooldown; + long duration; + int particles; + int freezeDuration; + int snowDuration; + int frozenWaterDuration; + int range; + boolean snowEnabled; + boolean bendSnow; + boolean damageEnabled; + double playerDamage; + double mobDamage; + boolean slowEnabled; + long slowDuration; + boolean restrictBiomes; + + Config(Player player) { + ConfigurationSection config = JedCoreConfig.getConfig(player); + + cooldown = config.getLong("Abilities.Water.FrostBreath.Cooldown"); + duration = config.getLong("Abilities.Water.FrostBreath.Duration"); + particles = config.getInt("Abilities.Water.FrostBreath.Particles"); + freezeDuration = config.getInt("Abilities.Water.FrostBreath.FrostDuration"); + snowDuration = config.getInt("Abilities.Water.FrostBreath.SnowDuration"); + frozenWaterDuration = config.getInt("Abilities.Water.FrostBreath.FrozenWaterDuration"); + range = config.getInt("Abilities.Water.FrostBreath.Range"); + snowEnabled = config.getBoolean("Abilities.Water.FrostBreath.Snow"); + bendSnow = config.getBoolean("Abilities.Water.FrostBreath.BendableSnow"); + damageEnabled = config.getBoolean("Abilities.Water.FrostBreath.Damage.Enabled"); + playerDamage = config.getDouble("Abilities.Water.FrostBreath.Damage.Player"); + mobDamage = config.getDouble("Abilities.Water.FrostBreath.Damage.Mob"); + slowEnabled = config.getBoolean("Abilities.Water.FrostBreath.Slow.Enabled"); + slowDuration = config.getLong("Abilities.Water.FrostBreath.Slow.Duration"); + restrictBiomes = config.getBoolean("Abilities.Water.FrostBreath.RestrictBiomes"); + } + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/HealingWaters.java b/src/com/jedk1/jedcore/ability/waterbending/HealingWaters.java index c5aa09f..07a5192 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/HealingWaters.java +++ b/src/com/jedk1/jedcore/ability/waterbending/HealingWaters.java @@ -3,7 +3,7 @@ import com.jedk1.jedcore.JCMethods; import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; -import com.jedk1.jedcore.util.LightManager; +import com.jedk1.jedcore.util.LightManagerUtil; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; @@ -13,9 +13,10 @@ import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; - import com.projectkorra.projectkorra.waterbending.util.WaterReturn; -import org.bukkit.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Server; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Damageable; @@ -32,236 +33,236 @@ public class HealingWaters extends HealingAbility implements AddonAbility { - private static long time = 0; - private static boolean enabled = true; - - public HealingWaters(Player player) { - super(player); - } - - public static void heal(Server server) { - if (enabled) { - if (System.currentTimeMillis() - time >= 1000) { - time = System.currentTimeMillis(); - for (Player player : server.getOnlinePlayers()) { - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - if (bPlayer != null && bPlayer.canBend(getAbility("HealingWaters"))) { - heal(player); - } - } - } - } - } - - @SuppressWarnings("deprecation") - private static void heal(Player player) { - if (inWater(player)) { - if (player.isSneaking()) { - Entity entity = GeneralMethods.getTargetedEntity(player, getRange(player), new ArrayList<>()); - if (entity instanceof LivingEntity && inWater(entity)) { - Location playerLoc = entity.getLocation(); - playerLoc.add(0, 1, 0); - JCMethods.displayColoredParticles("#9696E1", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f, 50); - ParticleEffect.WATER_WAKE.display(playerLoc, 25, 0, 0, 0, 0.05F); - giveHPToEntity((LivingEntity) entity); - emitLight(playerLoc); - emitLight(entity.getLocation()); - } - } else { - Location playerLoc = player.getLocation(); - playerLoc.add(0, 1, 0); - JCMethods.displayColoredParticles("#9696E1", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f, 50); - ParticleEffect.WATER_WAKE.display(playerLoc, 25, 0, 0, 0, 0.05F); - giveHP(player); - emitLight(playerLoc); - } - - } else if(hasWaterSupply(player) && player.isSneaking()) { - Entity entity = GeneralMethods.getTargetedEntity(player, getRange(player), new ArrayList<>()); - if (entity != null) { - if (entity instanceof LivingEntity) { - Damageable dLe = (Damageable) entity; - if (dLe.getHealth() < dLe.getMaxHealth()) { - Location playerLoc = entity.getLocation(); - playerLoc.add(0, 1, 0); - JCMethods.displayColoredParticles("#9696E1", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f, 50); - ParticleEffect.WATER_WAKE.display(playerLoc, 25, 0, 0, 0, 0.05F); - giveHPToEntity((LivingEntity) entity); - entity.setFireTicks(0); - Random rand = new Random(); - if (rand.nextInt(getDrainChance(player)) == 0) drainWaterSupply(player); - emitLight(playerLoc); - emitLight(entity.getLocation()); - } - } - } else { - Location playerLoc = player.getLocation(); - playerLoc.add(0, 1, 0); - - JCMethods.displayColoredParticles("#FFFFFF", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f, 50); - JCMethods.displayColoredParticles("#FFFFFF", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f); - - ParticleEffect.WATER_WAKE.display(playerLoc, 25, 0, 0, 0, 0.05F); - giveHP(player); - player.setFireTicks(0); - Random rand = new Random(); - if (rand.nextInt(getDrainChance(player)) == 0) drainWaterSupply(player); - emitLight(playerLoc); - } - } - } - - @SuppressWarnings("deprecation") - private static void giveHPToEntity(LivingEntity le) { - if (!le.isDead() && le.getHealth() < le.getMaxHealth()) { - applyHealingToEntity(le); - } - for (PotionEffect effect : le.getActivePotionEffects()) { - if (isNegativeEffect(effect.getType())) { - le.removePotionEffect(effect.getType()); - } - } - } - - private static void giveHP(Player player){ - if (!player.isDead() && player.getHealth() < 20) { - applyHealing(player); - } - for(PotionEffect effect : player.getActivePotionEffects()) { - if(isNegativeEffect(effect.getType())) { - if((effect.getType() == PotionEffectType.BLINDNESS) && Smokescreen.getBlindedTimes().containsKey(player.getName())) { - return; - } - player.removePotionEffect(effect.getType()); - } - } - } - - - - private static boolean inWater(Entity entity) { - Block block = entity.getLocation().getBlock(); - return isWater(block) && !TempBlock.isTempBlock(block); - } - - private static boolean hasWaterSupply(Player player){ - ItemStack heldItem = player.getInventory().getItemInMainHand(); - return (heldItem.isSimilar(WaterReturn.waterBottleItem()) || heldItem.getType() == Material.WATER_BUCKET); - - } - - private static void drainWaterSupply(Player player){ - ItemStack heldItem = player.getInventory().getItemInMainHand(); - ItemStack emptyBottle = new ItemStack(Material.GLASS_BOTTLE, 1); - if (heldItem.isSimilar(WaterReturn.waterBottleItem())) { - if (heldItem.getAmount() > 1) { - heldItem.setAmount(heldItem.getAmount() - 1); - HashMap cantFit = player.getInventory().addItem(emptyBottle); - for (int id : cantFit.keySet()) { - player.getWorld().dropItem(player.getEyeLocation(), cantFit.get(id)); - } - } else { - player.getInventory().setItemInMainHand(emptyBottle); - } - } - } - - @SuppressWarnings("deprecation") - private static void applyHealing(Player player) { - if (!RegionProtection.isRegionProtected(player, player.getLocation(), "HealingWaters")) - if(player.getHealth() < player.getMaxHealth()) { - player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 70, getPower(player))); - AirAbility.breakBreathbendingHold(player); - } - } - - @SuppressWarnings("deprecation") - private static void applyHealingToEntity(LivingEntity le) { - if (le.getHealth() < le.getMaxHealth()) { - le.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 70, 1)); - AirAbility.breakBreathbendingHold(le); - } - } - - public static int getPower(Player player) { - ConfigurationSection config = JedCoreConfig.getConfig(player); - return config.getInt("Abilities.Water.HealingWaters.Power"); - } - - public static double getRange(Player player) { - ConfigurationSection config = JedCoreConfig.getConfig(player); - return config.getDouble("Abilities.Water.HealingWaters.Range"); - } - - public static int getDrainChance(Player player) { - ConfigurationSection config = JedCoreConfig.getConfig(player); - return config.getInt("Abilities.Water.HealingWaters.DrainChance"); - } - - public static void emitLight(Location loc) { - ConfigurationSection config = JedCoreConfig.getConfig((Player)null); - if (config.getBoolean("Abilities.Water.HealingWaters.DynamicLight.Enabled")) { - int brightness = config.getInt("Abilities.Water.HealingWaters.DynamicLight.Brightness"); - long keepAlive = config.getLong("Abilities.Water.HealingWaters.DynamicLight.KeepAlive"); - - LightManager.createLight(loc).brightness(brightness).timeUntilFadeout(keepAlive).emit(); - } - } - - @Override - public long getCooldown() { - return 0; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "HealingWaters"; - } - - @Override - public boolean isHarmlessAbility() { - return true; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Water.HealingWaters.Description"); - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - enabled = config.getBoolean("Abilities.Water.HealingWaters.Enabled"); - return enabled; - } - - @Override - public void progress() {} + private static long time = 0; + private static boolean enabled = true; + + public HealingWaters(Player player) { + super(player); + } + + public static void heal(Server server) { + if (enabled) { + if (System.currentTimeMillis() - time >= 1000) { + time = System.currentTimeMillis(); + for (Player player : server.getOnlinePlayers()) { + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); + if (bPlayer != null && bPlayer.canBend(getAbility("HealingWaters"))) { + heal(player); + } + } + } + } + } + + @SuppressWarnings("deprecation") + private static void heal(Player player) { + if (inWater(player)) { + if (player.isSneaking()) { + Entity entity = GeneralMethods.getTargetedEntity(player, getRange(player), new ArrayList<>()); + if (entity instanceof LivingEntity && inWater(entity)) { + Location playerLoc = entity.getLocation(); + playerLoc.add(0, 1, 0); + JCMethods.displayColoredParticles("#9696E1", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f, 50); + ParticleEffect.WATER_WAKE.display(playerLoc, 25, 0, 0, 0, 0.05F); + giveHPToEntity((LivingEntity) entity); + emitLight(playerLoc); + emitLight(entity.getLocation()); + } + } else { + Location playerLoc = player.getLocation(); + playerLoc.add(0, 1, 0); + JCMethods.displayColoredParticles("#9696E1", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f, 50); + ParticleEffect.WATER_WAKE.display(playerLoc, 25, 0, 0, 0, 0.05F); + giveHP(player); + emitLight(playerLoc); + } + + } else if(hasWaterSupply(player) && player.isSneaking()) { + Entity entity = GeneralMethods.getTargetedEntity(player, getRange(player), new ArrayList<>()); + if (entity != null) { + if (entity instanceof LivingEntity) { + Damageable dLe = (Damageable) entity; + if (dLe.getHealth() < dLe.getMaxHealth()) { + Location playerLoc = entity.getLocation(); + playerLoc.add(0, 1, 0); + JCMethods.displayColoredParticles("#9696E1", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f, 50); + ParticleEffect.WATER_WAKE.display(playerLoc, 25, 0, 0, 0, 0.05F); + giveHPToEntity((LivingEntity) entity); + entity.setFireTicks(0); + Random rand = new Random(); + if (rand.nextInt(getDrainChance(player)) == 0) drainWaterSupply(player); + emitLight(playerLoc); + emitLight(entity.getLocation()); + } + } + } else { + Location playerLoc = player.getLocation(); + playerLoc.add(0, 1, 0); + + JCMethods.displayColoredParticles("#FFFFFF", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f, 50); + JCMethods.displayColoredParticles("#FFFFFF", playerLoc, 3, Math.random(), Math.random(), Math.random(), 0f); + + ParticleEffect.WATER_WAKE.display(playerLoc, 25, 0, 0, 0, 0.05F); + giveHP(player); + player.setFireTicks(0); + Random rand = new Random(); + if (rand.nextInt(getDrainChance(player)) == 0) drainWaterSupply(player); + emitLight(playerLoc); + } + } + } + + @SuppressWarnings("deprecation") + private static void giveHPToEntity(LivingEntity le) { + if (!le.isDead() && le.getHealth() < le.getMaxHealth()) { + applyHealingToEntity(le); + } + for (PotionEffect effect : le.getActivePotionEffects()) { + if (isNegativeEffect(effect.getType())) { + le.removePotionEffect(effect.getType()); + } + } + } + + private static void giveHP(Player player){ + if (!player.isDead() && player.getHealth() < 20) { + applyHealing(player); + } + for(PotionEffect effect : player.getActivePotionEffects()) { + if(isNegativeEffect(effect.getType())) { + if((effect.getType() == PotionEffectType.BLINDNESS) && Smokescreen.getBlindedTimes().containsKey(player.getName())) { + return; + } + player.removePotionEffect(effect.getType()); + } + } + } + + + + private static boolean inWater(Entity entity) { + Block block = entity.getLocation().getBlock(); + return isWater(block) && !TempBlock.isTempBlock(block); + } + + private static boolean hasWaterSupply(Player player){ + ItemStack heldItem = player.getInventory().getItemInMainHand(); + return (heldItem.isSimilar(WaterReturn.waterBottleItem()) || heldItem.getType() == Material.WATER_BUCKET); + + } + + private static void drainWaterSupply(Player player){ + ItemStack heldItem = player.getInventory().getItemInMainHand(); + ItemStack emptyBottle = new ItemStack(Material.GLASS_BOTTLE, 1); + if (heldItem.isSimilar(WaterReturn.waterBottleItem())) { + if (heldItem.getAmount() > 1) { + heldItem.setAmount(heldItem.getAmount() - 1); + HashMap cantFit = player.getInventory().addItem(emptyBottle); + for (int id : cantFit.keySet()) { + player.getWorld().dropItem(player.getEyeLocation(), cantFit.get(id)); + } + } else { + player.getInventory().setItemInMainHand(emptyBottle); + } + } + } + + @SuppressWarnings("deprecation") + private static void applyHealing(Player player) { + if (!RegionProtection.isRegionProtected(player, player.getLocation(), "HealingWaters")) + if(player.getHealth() < player.getMaxHealth()) { + player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 70, getPower(player))); + AirAbility.breakBreathbendingHold(player); + } + } + + @SuppressWarnings("deprecation") + private static void applyHealingToEntity(LivingEntity le) { + if (le.getHealth() < le.getMaxHealth()) { + le.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 70, 1)); + AirAbility.breakBreathbendingHold(le); + } + } + + public static int getPower(Player player) { + ConfigurationSection config = JedCoreConfig.getConfig(player); + return config.getInt("Abilities.Water.HealingWaters.Power"); + } + + public static double getRange(Player player) { + ConfigurationSection config = JedCoreConfig.getConfig(player); + return config.getDouble("Abilities.Water.HealingWaters.Range"); + } + + public static int getDrainChance(Player player) { + ConfigurationSection config = JedCoreConfig.getConfig(player); + return config.getInt("Abilities.Water.HealingWaters.DrainChance"); + } + + public static void emitLight(Location loc) { + ConfigurationSection config = JedCoreConfig.getConfig((Player)null); + if (config.getBoolean("Abilities.Water.HealingWaters.DynamicLight.Enabled")) { + int brightness = config.getInt("Abilities.Water.HealingWaters.DynamicLight.Brightness"); + long keepAlive = config.getLong("Abilities.Water.HealingWaters.DynamicLight.KeepAlive"); + + LightManagerUtil.createLight(loc).brightness(brightness).timeUntilFadeout(keepAlive).emit(); + } + } + + @Override + public long getCooldown() { + return 0; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "HealingWaters"; + } + + @Override + public boolean isHarmlessAbility() { + return true; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Water.HealingWaters.Description"); + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + enabled = config.getBoolean("Abilities.Water.HealingWaters.Enabled"); + return enabled; + } + + @Override + public void progress() {} } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/IceClaws.java b/src/com/jedk1/jedcore/ability/waterbending/IceClaws.java index 5594a0c..a9142b5 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/IceClaws.java +++ b/src/com/jedk1/jedcore/ability/waterbending/IceClaws.java @@ -8,276 +8,323 @@ import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; - import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.inventory.MainHand; import org.bukkit.potion.PotionEffectType; public class IceClaws extends IceAbility implements AddonAbility { - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.CHARGE_DURATION) - private long chargeUp; - private int slowDur; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute(Attribute.RANGE) - private double range; - private boolean throwable; - - private Location head; - private Location origin; - private boolean launched; - - public IceClaws(Player player) { - super(player); - if (!bPlayer.canBend(this) || !bPlayer.canIcebend()) { - return; - } - - if (hasAbility(player, IceClaws.class)) { - IceClaws ic = getAbility(player, IceClaws.class); - if (!ic.throwable) { - ic.remove(); - } - return; - } - - setFields(); - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Water.IceClaws.Cooldown"); - chargeUp = config.getLong("Abilities.Water.IceClaws.ChargeTime"); - slowDur = config.getInt("Abilities.Water.IceClaws.SlowDuration")/50; - damage = config.getDouble("Abilities.Water.IceClaws.Damage"); - range = config.getDouble("Abilities.Water.IceClaws.Range"); - throwable = config.getBoolean("Abilities.Water.IceClaws.Throwable"); - - applyModifiers(); - } - - private void applyModifiers() { - cooldown -= ((long) getNightFactor(cooldown) - cooldown); - damage = getNightFactor(damage); - range = getNightFactor(range); - } - - @Override - public void progress() { - if (player == null || player.isDead() || !player.isOnline()) { - remove(); - return; - } - if (!bPlayer.canBendIgnoreCooldowns(this)) { - remove(); - return; - } - if (System.currentTimeMillis() > getStartTime() + chargeUp) { - if (!launched && throwable) { - displayClaws(); - } else { - if (!shoot()) { - remove(); - } - } - } else if (player.isSneaking()) { - displayChargeUp(); - } else { - remove(); - } - } - - public boolean shoot() { - for (double i = 0; i < 1; i+=.5) { - head.add(origin.clone().getDirection().multiply(.5)); - if (origin.distance(head) >= range) return false; - if (!isTransparent(head.getBlock())) return false; - GeneralMethods.displayColoredParticle("66FFFF", head); - GeneralMethods.displayColoredParticle("CCFFFF", head); - ParticleEffect.SNOW_SHOVEL.display(head, 1, 0, 0, 0, 0); - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(head, 1.5)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand)) { - freezeEntity((LivingEntity) entity); - return false; - } - } - } - return true; - - } - - public static void throwClaws(Player player) { - if (hasAbility(player, IceClaws.class)) { - IceClaws ic = getAbility(player, IceClaws.class); - if (!ic.launched && player.isSneaking()) { - ic.launched = true; - ic.origin = ic.player.getEyeLocation(); - ic.head = ic.origin.clone(); - } - } - } - - public Location getRightHandPos() { - return GeneralMethods.getRightSide(player.getLocation(), .55).add(0, 1.2, 0); - } - - private void displayClaws() { - Location location = getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.75D)).toLocation(player.getWorld()); - GeneralMethods.displayColoredParticle("66FFFF", location); - GeneralMethods.displayColoredParticle("CCFFFF", location); - } - - private void displayChargeUp() { - Location location = getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.75D)).toLocation(player.getWorld()); - ParticleEffect.WATER_SPLASH.display(location, 1, Math.random()/3, Math.random()/3, Math.random()/3, 0.0); - } - - public static boolean freezeEntity(Player player, LivingEntity entity) { - if (hasAbility(player, IceClaws.class)) { - getAbility(player, IceClaws.class).freezeEntity(entity); - return true; - } - return false; - } - - private void freezeEntity(LivingEntity entity) { - if (entity.hasPotionEffect(PotionEffectType.SPEED)) { - entity.removePotionEffect(PotionEffectType.SPEED); - } - // todo: doesnt seem to be affecting mobs? frostbreath does. - entity.addPotionEffect(JedCore.plugin.getPotionEffectAdapter().getSlownessEffect(slowDur, 3)); - bPlayer.addCooldown(this); - remove(); - DamageHandler.damageEntity(entity, damage, this); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return head; - } - - @Override - public String getName() { - return "IceClaws"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Water.IceClaws.Description"); - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getChargeUp() { - return chargeUp; - } - - public void setChargeUp(long chargeUp) { - this.chargeUp = chargeUp; - } - - public int getSlowDuration() { - return slowDur; - } - - public void setSlowDuration(int slowDuration) { - this.slowDur = slowDuration; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public double getRange() { - return range; - } - - public void setRange(double range) { - this.range = range; - } - - public boolean isThrowable() { - return throwable; - } - - public void setThrowable(boolean throwable) { - this.throwable = throwable; - } - - public Location getHead() { - return head; - } - - public void setHead(Location head) { - this.head = head; - } - - public Location getOrigin() { - return origin; - } - - public void setOrigin(Location origin) { - this.origin = origin; - } - - public boolean isLaunched() { - return launched; - } - - public void setLaunched(boolean launched) { - this.launched = launched; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Water.IceClaws.Enabled"); - } + @Attribute(Attribute.COOLDOWN) + private long punchCooldown; + @Attribute(Attribute.COOLDOWN) + private long throwCooldown; + @Attribute(Attribute.CHARGE_DURATION) + private long chargeUp; + private int punchSlowDur; + private int throwSlowDur; + private int punchSlownessLevel; + private int throwSlownessLevel; + @Attribute(Attribute.DAMAGE) + private double punchDamage; + @Attribute(Attribute.DAMAGE) + private double throwDamage; + @Attribute(Attribute.RANGE) + private double range; + private boolean throwable; + private double throwSpeed; + + private Location head; + private Location origin; + private boolean launched; + + private Boolean iceInMainHand = null; + + public IceClaws(Player player) { + super(player); + if (!bPlayer.canBend(this) || !bPlayer.canIcebend()) { + return; + } + + if (hasAbility(player, IceClaws.class)) { + IceClaws ic = getAbility(player, IceClaws.class); + if (!ic.throwable) { + ic.remove(); + } + return; + } + + setFields(); + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + punchCooldown = config.getLong("Abilities.Water.IceClaws.Punch.Cooldown", 4000); + punchDamage = config.getDouble("Abilities.Water.IceClaws.Punch.Damage", 2.0); + punchSlownessLevel = config.getInt("Abilities.Water.IceClaws.Punch.Slowness", 3); + punchSlowDur = config.getInt("Abilities.Water.IceClaws.Punch.SlowDuration", 5000); + + throwCooldown = config.getLong("Abilities.Water.IceClaws.Throw.Cooldown", 4000); + throwDamage = config.getDouble("Abilities.Water.IceClaws.Throw.Damage", 2.0); + throwSlownessLevel = config.getInt("Abilities.Water.IceClaws.Throw.Slowness", 3); + throwSlowDur = config.getInt("Abilities.Water.IceClaws.Throw.SlowDuration", 5000); + throwSpeed = config.getDouble("Abilities.Water.IceClaws.Throw.Speed", 1.0); + + chargeUp = config.getLong("Abilities.Water.IceClaws.ChargeTime", 1000); + range = config.getDouble("Abilities.Water.IceClaws.Range", 10); + throwable = config.getBoolean("Abilities.Water.IceClaws.Throwable", true); + + applyModifiers(); + } + + private void applyModifiers() { + punchCooldown -= ((long) getNightFactor(punchCooldown) - punchCooldown); + throwCooldown -= ((long) getNightFactor(throwCooldown) - throwCooldown); + punchDamage = getNightFactor(punchDamage); + throwDamage = getNightFactor(throwDamage); + range = getNightFactor(range); + } + + @Override + public void progress() { + if (player == null || player.isDead() || !player.isOnline()) { + remove(); + return; + } + if (!bPlayer.canBendIgnoreCooldowns(this)) { + remove(); + return; + } + if (System.currentTimeMillis() > getStartTime() + chargeUp) { + if (!launched && throwable) { + displayClaws(); + } else { + if (!shoot()) { + remove(); + } + } + } else if (player.isSneaking()) { + displayChargeUp(); + } else { + remove(); + } + } + + + public static void swapHands(Player player) { + ConfigurationSection config = JedCoreConfig.getConfig(player); + if (!config.getBoolean("Abilities.Water.IceClaws.AllowHandSwap", true)) return; + IceClaws ic = getAbility(player, IceClaws.class); + if (ic == null) + return; + if (ic.iceInMainHand == null) + ic.iceInMainHand = true; + else ic.iceInMainHand = !ic.iceInMainHand; + } + + public Location getRightHandPos() { + return (player.getMainHand() == MainHand.RIGHT == ((iceInMainHand == null) || iceInMainHand) ? + GeneralMethods.getRightSide(player.getLocation(), .55) : + GeneralMethods.getLeftSide(player.getLocation(), .55)).add(0, 1.2, 0); + } + + public boolean shoot() { + for (double i = 0; i < 1; i += throwSpeed) { + head.add(origin.clone().getDirection().multiply(throwSpeed)); + if (origin.distance(head) >= range) return false; + if (!isTransparent(head.getBlock())) return false; + GeneralMethods.displayColoredParticle("66FFFF", head); + GeneralMethods.displayColoredParticle("CCFFFF", head); + ParticleEffect.SNOW_SHOVEL.display(head, 1, 0, 0, 0, 0); + for (Entity entity : GeneralMethods.getEntitiesAroundPoint(head, 1.5)) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand)) { + freezeEntity((LivingEntity) entity, false); + return false; + } + } + } + return true; + } + + public static void throwClaws(Player player) { + if (hasAbility(player, IceClaws.class)) { + IceClaws ic = getAbility(player, IceClaws.class); + if (!ic.launched && player.isSneaking()) { + ic.launched = true; + ic.origin = ic.player.getEyeLocation(); + ic.head = ic.origin.clone(); + } + } + } + + private void displayClaws() { + Location location = getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.75D)).toLocation(player.getWorld()); + GeneralMethods.displayColoredParticle("66FFFF", location); + GeneralMethods.displayColoredParticle("CCFFFF", location); + } + + private void displayChargeUp() { + Location location = getRightHandPos().toVector().add(player.getEyeLocation().getDirection().clone().multiply(.75D)).toLocation(player.getWorld()); + ParticleEffect.WATER_SPLASH.display(location, 1, Math.random()/3, Math.random()/3, Math.random()/3, 0.0); + } + + public static boolean freezeEntity(Player player, LivingEntity entity) { + if (hasAbility(player, IceClaws.class)) { + getAbility(player, IceClaws.class).freezeEntity(entity); + return true; + } + return false; + } + + private void freezeEntity(LivingEntity entity) { + freezeEntity(entity, true); + } + + private void freezeEntity(LivingEntity entity, boolean isPunch) { + if (entity.hasPotionEffect(PotionEffectType.SPEED)) { + entity.removePotionEffect(PotionEffectType.SPEED); + } + int duration = isPunch ? punchSlowDur : throwSlowDur; + int level = isPunch ? punchSlownessLevel : throwSlownessLevel; + entity.addPotionEffect(JedCore.plugin.getPotionEffectAdapter().getSlownessEffect(duration, level)); + bPlayer.addCooldown(this); + remove(); + DamageHandler.damageEntity(entity, isPunch ? punchDamage : throwDamage, this); + } + + @Override + public long getCooldown() { + return launched ? throwCooldown : punchCooldown; + } + + @Override + public Location getLocation() { + return head; + } + + @Override + public String getName() { + return "IceClaws"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Water.IceClaws.Description"); + } + + public void setPunchCooldown(long punchCooldown) { this.punchCooldown = punchCooldown; } + public long getPunchCooldown() { return punchCooldown; } + public void setThrowCooldown(long throwCooldown) { this.throwCooldown = throwCooldown; } + public long getThrowCooldown() { return throwCooldown; } + public void setPunchDamage(double punchDamage) { this.punchDamage = punchDamage; } + public double getPunchDamage() { return punchDamage; } + public void setThrowDamage(double throwDamage) { this.throwDamage = throwDamage; } + public double getThrowDamage() { return throwDamage; } + public void setPunchSlowDur(int punchSlowDur) { this.punchSlowDur = punchSlowDur; } + public int getPunchSlowDur() { return punchSlowDur; } + public void setThrowSlowDur(int throwSlowDur) { this.throwSlowDur = throwSlowDur; } + public int getThrowSlowDur() { return throwSlowDur; } + + public double getRange() { + return range; + } + + public void setRange(double range) { + this.range = range; + } + + public boolean isThrowable() { + return throwable; + } + + public void setThrowable(boolean throwable) { + this.throwable = throwable; + } + + public Location getHead() { + return head; + } + + public void setHead(Location head) { + this.head = head; + } + + public Location getOrigin() { + return origin; + } + + public void setOrigin(Location origin) { + this.origin = origin; + } + + public boolean isLaunched() { + return launched; + } + + public void setLaunched(boolean launched) { + this.launched = launched; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Water.IceClaws.Enabled"); + } + + public int getPunchSlownessLevel() { + return punchSlownessLevel; + } + + public void setPunchSlownessLevel(int punchSlownessLevel) { + this.punchSlownessLevel = punchSlownessLevel; + } + + public int getThrowSlownessLevel() { + return throwSlownessLevel; + } + + public void setThrowSlownessLevel(int throwSlownessLevel) { + this.throwSlownessLevel = throwSlownessLevel; + } + + public double getThrowSpeed() { + return throwSpeed; + } + + public void setThrowSpeed(double throwSpeed) { + this.throwSpeed = throwSpeed; + } } \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/IcePassive.java b/src/com/jedk1/jedcore/ability/waterbending/IcePassive.java index 9477a8c..fc28793 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/IcePassive.java +++ b/src/com/jedk1/jedcore/ability/waterbending/IcePassive.java @@ -4,9 +4,9 @@ import com.jedk1.jedcore.configuration.JedCoreConfig; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.Element; +import com.projectkorra.projectkorra.ability.ElementalAbility; import com.projectkorra.projectkorra.ability.IceAbility; import com.projectkorra.projectkorra.util.ParticleEffect; - import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.BlockFace; @@ -20,7 +20,6 @@ public class IcePassive { - @SuppressWarnings("deprecation") public static void handleSkating() { Map> resultCache = new HashMap<>(); @@ -40,15 +39,22 @@ public static void handleSkating() { int speedFactor = result.second; if (!enabled) continue; + if (JCMethods.isDisabledWorld(player.getWorld())) continue; + if (!player.isOnGround()) continue; + if (!player.isSprinting()) continue; + if (!ElementalAbility.isIce(player.getLocation().getBlock().getRelative(BlockFace.DOWN))) continue; BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - if (bPlayer != null && bPlayer.canIcebend() && bPlayer.isElementToggled(Element.WATER) && bPlayer.hasElement(Element.WATER) && !JCMethods.isDisabledWorld(player.getWorld())) { - if (player.isSprinting() && IceAbility.isIce(player.getLocation().getBlock().getRelative(BlockFace.DOWN)) && player.isOnGround()) { - ParticleEffect.SNOW_SHOVEL.display(player.getLocation().clone().add(0, 0.2, 0), 15, Math.random()/2, Math.random()/2, Math.random()/2, 0); - player.removePotionEffect(PotionEffectType.SPEED); - player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 60, speedFactor)); - } - } + + if (bPlayer == null) continue; + if (!bPlayer.canIcebend()) continue; + if (!bPlayer.isPassiveToggled(Element.WATER)) continue; + + if (!player.hasPermission("bending.ability.IceSkate")) continue; + + ParticleEffect.SNOW_SHOVEL.display(player.getLocation().clone().add(0, 0.2, 0), 15, Math.random()/2, Math.random()/2, Math.random()/2, 0); + player.removePotionEffect(PotionEffectType.SPEED); + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 60, speedFactor)); } } diff --git a/src/com/jedk1/jedcore/ability/waterbending/IceWall.java b/src/com/jedk1/jedcore/ability/waterbending/IceWall.java index bc5471a..b9b0f87 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/IceWall.java +++ b/src/com/jedk1/jedcore/ability/waterbending/IceWall.java @@ -1,29 +1,11 @@ package com.jedk1.jedcore.ability.waterbending; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Random; - +import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; +import com.jedk1.jedcore.util.ThreadUtil; +import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.*; import com.projectkorra.projectkorra.attribute.Attribute; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Sound; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.util.Vector; - -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.airbending.AirBlast; import com.projectkorra.projectkorra.earthbending.EarthSmash; import com.projectkorra.projectkorra.firebending.FireBlast; import com.projectkorra.projectkorra.firebending.FireBlastCharged; @@ -33,631 +15,596 @@ import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.waterbending.Torrent; import com.projectkorra.projectkorra.waterbending.ice.IceBlast; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; -public class IceWall extends IceAbility implements AddonAbility { +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Random; - public static List instances = new ArrayList<>(); - @Attribute(Attribute.HEIGHT) - private int maxHeight; - private int minHeight; - private int width; - @Attribute(Attribute.RANGE) - private int range; - @Attribute("Health") - private int maxHealth; - private int minHealth; - @Attribute(Attribute.DAMAGE) - private double damage; - @Attribute(Attribute.COOLDOWN) - private long cooldown; - - public static boolean stackable; - - public static boolean lifetimeEnabled; - public static long lifetimeTime; - - public int torrentDamage; - public int torrentFreezeDamage; - public int iceBlastDamage; - public int fireBlastDamage; - public int fireBlastChargedDamage; - public int lightningDamage; - public int combustionDamage; - public int earthSmashDamage; - public int airBlastDamage; - - public boolean isWallDoneFor = false; - public List affectedBlocks = new ArrayList<>(); - - private boolean rising = false; - private long lastDamageTime = 0; - private long lifetime = 0; - private int wallHealth; - private int tankedDamage; - private final List lastBlocks = new ArrayList<>(); - private final List tempBlocks = new ArrayList<>(); - - Random rand = new Random(); - - public IceWall(Player player) { - super(player); - if (!bPlayer.canBendIgnoreCooldowns(this) || !bPlayer.canIcebend()) { - return; - } - - setFields(); - Block b = getSourceBlock(player, (int) (range * getNightFactor(player.getWorld()))); - - if (b == null) - return; - - else { - for (IceWall iw : instances) { - if (iw.affectedBlocks.contains(b)) { - iw.collapse(player, false); - return; - } - } - - if (isWaterbendable(b)) { - if (!bPlayer.canBend(this)) { - return; - } - - wallHealth = (int) (((rand.nextInt((maxHealth - minHealth) + 1)) + minHealth) * getNightFactor(player.getWorld())); - loadAffectedBlocks(player, b); - lifetime = System.currentTimeMillis() + lifetimeTime; - } - } - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - setMaxHeight(config.getInt("Abilities.Water.IceWall.MaxHeight")); - setMinHeight(config.getInt("Abilities.Water.IceWall.MinHeight")); - setWidth(config.getInt("Abilities.Water.IceWall.Width")); - range = config.getInt("Abilities.Water.IceWall.Range"); - maxHealth = config.getInt("Abilities.Water.IceWall.MaxWallHealth"); - minHealth = config.getInt("Abilities.Water.IceWall.MinWallHealth"); - damage = config.getDouble("Abilities.Water.IceWall.Damage"); - cooldown = config.getLong("Abilities.Water.IceWall.Cooldown"); - stackable = config.getBoolean("Abilities.Water.IceWall.Stackable"); - lifetimeEnabled = config.getBoolean("Abilities.Water.IceWall.LifeTime.Enabled"); - lifetimeTime = config.getLong("Abilities.Water.IceWall.LifeTime.Duration"); - torrentDamage = config.getInt("Abilities.Water.IceWall.WallDamage.Torrent"); - torrentFreezeDamage = config.getInt("Abilities.Water.IceWall.WallDamage.TorrentFreeze"); - iceBlastDamage = config.getInt("Abilities.Water.IceWall.WallDamage.IceBlast"); - fireBlastDamage = config.getInt("Abilities.Water.IceWall.WallDamage.Fireblast"); - fireBlastChargedDamage = config.getInt("Abilities.Water.IceWall.WallDamage.FireblastCharged"); - lightningDamage = config.getInt("Abilities.Water.IceWall.WallDamage.Lightning"); - combustionDamage = config.getInt("Abilities.Water.IceWall.WallDamage.Combustion"); - earthSmashDamage = config.getInt("Abilities.Water.IceWall.WallDamage.EarthSmash"); - airBlastDamage = config.getInt("Abilities.Water.IceWall.WallDamage.AirBlast"); - } - - public Block getSourceBlock(Player player, int range) { - Vector direction = player.getEyeLocation().getDirection().normalize(); - - for (int i = 0; i <= range; i++) { - Block b = player.getEyeLocation().add(direction.clone().multiply((double) i)).getBlock(); - - if (isBendable(b)) return b; - } - - return null; - } - - public boolean isBendable(Block b) { - return isWater(b) || isIce(b.getType()) || isSnow(b.getType()); - } - - public void loadAffectedBlocks(Player player, Block block) { - Vector direction = player.getEyeLocation().getDirection().normalize(); - - double ox, oy, oz; - ox = -direction.getZ(); - oy = 0; - oz = direction.getX(); - - Vector orth = new Vector(ox, oy, oz); - orth = orth.normalize(); - - Location origin = block.getLocation(); - - World world = origin.getWorld(); - - int width = (int) (getWidth() * getNightFactor(world)); - int minHeight = (int) (getMinHeight() * getNightFactor(world)); - int maxHeight = (int) (getMaxHeight() * getNightFactor(world)); - - int height = minHeight; - boolean increasingHeight = true; - for (int i = -(width / 2); i < width / 2; i++) { - Block b = world.getBlockAt(origin.clone().add(orth.clone().multiply((double) i))); - - if (ElementalAbility.isAir(b.getType())) { - while (ElementalAbility.isAir(b.getType())) { - if (b.getY() < 0) - return; - - b = b.getRelative(BlockFace.DOWN); - } - } - - if (!ElementalAbility.isAir(b.getRelative(BlockFace.UP).getType())) { - while (!ElementalAbility.isAir(b.getRelative(BlockFace.UP).getType())) { - if (b.getY() > b.getWorld().getMaxHeight()) - return; - - b = b.getRelative(BlockFace.UP); - } - } - - if (!stackable && isIceWallBlock(b)) { - continue; - } - - if (isBendable(b)) { - affectedBlocks.add(b); - for (int h = 1; h <= height; h++) { - Block up = b.getRelative(BlockFace.UP, h); - if (ElementalAbility.isAir(up.getType())) { - affectedBlocks.add(up); - } - } - - if (height < maxHeight && increasingHeight) - height++; - - if (i == 0) - increasingHeight = false; - - if (!increasingHeight && height > minHeight) - height--; - - lastBlocks.add(b); - } - - } - - bPlayer.addCooldown(this); - rising = true; - instances.add(this); - } - - @Override - public void progress() { - if (rising) { - if (lastBlocks.isEmpty()) { - rising = false; - return; - } - - List theseBlocks = new ArrayList<>(lastBlocks); - - lastBlocks.clear(); - - for (Block b : theseBlocks) { - TempBlock tb = new TempBlock(b, Material.ICE.createBlockData()); - tempBlocks.add(tb); - - playIcebendingSound(b.getLocation()); - - Block up = b.getRelative(BlockFace.UP); - - if (affectedBlocks.contains(up)) - lastBlocks.add(up); - } - } - - if (System.currentTimeMillis() > lifetime && lifetimeEnabled) { - collapse(player, false); - } - } - - public void damageWall(Player player, int damage) { - long noDamageTicks = 1000; - if (System.currentTimeMillis() < lastDamageTime + noDamageTicks) - return; - - lastDamageTime = System.currentTimeMillis(); - tankedDamage += damage; - if (tankedDamage >= wallHealth) { - collapse(player, true); - } - } - - public void collapse(Player player, boolean forceful) { - if (rising) - return; - - remove(player, forceful); - } - - public void remove(Player player, boolean forceful) { - for (TempBlock tb : tempBlocks) { - if (tb != null) { - tb.revertBlock(); - - ParticleEffect.BLOCK_CRACK.display(tb.getLocation(), 5, 0, 0, 0, 0, Material.PACKED_ICE.createBlockData()); - tb.getLocation().getWorld().playSound(tb.getLocation(), Sound.BLOCK_GLASS_BREAK, 5f, 5f); - - for (Entity e : GeneralMethods.getEntitiesAroundPoint(tb.getLocation(), 2.5)) { - if (e.getEntityId() != player.getEntityId()) { - if (e instanceof LivingEntity) { - DamageHandler.damageEntity(e, damage * getNightFactor(player.getWorld()), this); - if (forceful) { - ((LivingEntity) e).setNoDamageTicks(0); - } - } - } - } - } - } - - tempBlocks.clear(); - - isWallDoneFor = true; - remove(); - } - - public void remove() { - for (TempBlock tb : tempBlocks) { - if (tb != null) { - tb.revertBlock(); - } - } - - tempBlocks.clear(); - - instances.remove(this); - super.remove(); - } - - public static void removeDeadInstances() { - for (int i = 0; i < instances.size(); i++) { - IceWall iw = instances.get(i); - if (iw.isWallDoneFor) { - instances.remove(i); - } - } - } - - public static void collisionDamage(Entity entity, double travelledDistance, Vector difference, Player instigator) { - for (IceWall iw : IceWall.instances) { - for (Block b : iw.affectedBlocks) { - if (entity.getLocation().getWorld() == b.getLocation().getWorld() && entity.getLocation().distance(b.getLocation()) < 2) { - double damage = ((travelledDistance - 5.0) < 0 ? 0 : travelledDistance - 5.0) / (difference.length()); - iw.damageWall(instigator, (int) damage); - } - } - } - } - - public static boolean checkExplosions(Location location, Entity entity) { - for (IceWall iw : IceWall.instances) { - for (Block b : iw.affectedBlocks) { - if (location.getWorld() == b.getLocation().getWorld() && location.distance(b.getLocation()) < 2) { - - for (Entity e : GeneralMethods.getEntitiesAroundPoint(location, 3)) { - if (e instanceof LivingEntity) { - ((LivingEntity) e).damage(7, entity); - } - } - return true; - } - } - } - return false; - } - - public static boolean isIceWallBlock(Block block) { - for (IceWall iw : IceWall.instances) { - if (iw.affectedBlocks.contains(block)) { - return true; - } - } - return false; - } - - public static void removeAll() { - Iterator it = instances.iterator(); - while (it.hasNext()) { - it.next().remove(); - it.remove(); - } - } - - public static void progressAll() { - /* - for (IceWall iw : IceWall.instances) { - iw.progress(); - } - */ - - ListIterator iwli = IceWall.instances.listIterator(); - - while (iwli.hasNext()) { - IceWall iw = iwli.next(); - for (Torrent t : getAbilities(Torrent.class)) { - if (t.getLocation() == null) continue; - for (int i = 0; i < t.getLaunchedBlocks().size(); i++) { - TempBlock tb = t.getLaunchedBlocks().get(i); - - for (Block ice : iw.affectedBlocks) { - if (ice.getLocation().getWorld() == tb.getLocation().getWorld() && ice.getLocation().distance(tb.getLocation()) <= 2) { - if (t.isFreeze()) - iw.damageWall(t.getPlayer(), (int) (iw.torrentFreezeDamage * getNightFactor(ice.getWorld()))); - else - iw.damageWall(t.getPlayer(), (int) (iw.torrentDamage * getNightFactor(ice.getWorld()))); - - if (!iw.isWallDoneFor) - t.setFreeze(false); - } - } - } - } - - for (IceBlast ib : getAbilities(IceBlast.class)) { - if (ib.getLocation() == null) continue; - for (Block ice : iw.affectedBlocks) { - if (ib.source == null) - break; - - if (ice.getLocation().getWorld() == ib.source.getLocation().getWorld() && ice.getLocation().distance(ib.source.getLocation()) <= 2) { - iw.damageWall(ib.getPlayer(), (int) (iw.iceBlastDamage * getNightFactor(ice.getWorld()))); - - if (!iw.isWallDoneFor) - ib.remove(); - } - } - } - - for (FireBlastCharged fb : getAbilities(FireBlastCharged.class)) { - if (fb.getLocation() == null) continue; - for (Block ice : iw.affectedBlocks) { - if (ice.getLocation().getWorld() == fb.getLocation().getWorld() && fb.getLocation().distance(ice.getLocation()) <= 1.5) { - iw.damageWall(fb.getPlayer(), iw.fireBlastChargedDamage); - - if (!iw.isWallDoneFor) fb.remove(); - } - } - } - - for (FireBlast fb : getAbilities(FireBlast.class)) { - if (fb.getLocation() == null) continue; - for (Block ice : iw.affectedBlocks) { - if (ice.getLocation().getWorld() == fb.getLocation().getWorld() && fb.getLocation().distance(ice.getLocation()) <= 1.5) { - iw.damageWall(fb.getPlayer(), iw.fireBlastDamage); - - if (!iw.isWallDoneFor) fb.remove(); - } - } - } - - for (EarthSmash es : getAbilities(EarthSmash.class)) { - if (es.getLocation() == null) continue; - for (Block ice : iw.affectedBlocks) { - if (es.getState() == EarthSmash.State.SHOT) { - for (int j = 0; j < es.getBlocks().size(); j++) { - Block b = es.getBlocks().get(j); - if (ice.getLocation().getWorld() == b.getLocation().getWorld() && b.getLocation().distance(ice.getLocation()) <= 2) { - iw.damageWall(es.getPlayer(), iw.earthSmashDamage); - - if (!iw.isWallDoneFor) { - for (Block block : es.getBlocksIncludingInner()) { - if (block != null && !ElementalAbility.isAir(block.getType())) { - ParticleEffect.BLOCK_CRACK.display(block.getLocation(), 5, 0, 0, 0, 0, block.getBlockData().clone()); - } - } - es.remove(); - } - } - } - } - } - } - - for (Lightning l : getAbilities(Lightning.class)) { - for (Lightning.Arc arc : l.getArcs()) { - for (Block ice : iw.affectedBlocks) { - for (Location loc : arc.getPoints()) { - if (ice.getLocation().getWorld() == loc.getWorld() && loc.distance(ice.getLocation()) <= 1.5) { - iw.damageWall(l.getPlayer(), (int) (FireAbility.getDayFactor(iw.lightningDamage, ice.getWorld()))); - - if (!iw.isWallDoneFor) - l.remove(); - } - } - } - } - } - - for (AirBlast ab : getAbilities(AirBlast.class)) { - if (ab.getLocation() == null) continue; - for (Block ice : iw.affectedBlocks) { - if (ice.getLocation().getWorld() == ab.getLocation().getWorld() && ab.getLocation().distance(ice.getLocation()) <= 1.5) { - iw.damageWall(ab.getPlayer(), iw.airBlastDamage); - - if (!iw.isWallDoneFor) ab.remove(); - } - } - } - - for (CoreAbility ca : getAbilities(getAbility("Combustion").getClass())) { - if (ca.getLocation() == null) continue; - for (Block ice : iw.affectedBlocks) { - if (ice.getLocation().getWorld() == ca.getLocation().getWorld() && ca.getLocation().distance(ice.getLocation()) <= 1.5) { - iw.damageWall(ca.getPlayer(), iw.combustionDamage); - if (!iw.isWallDoneFor) ca.remove(); - } - } - } - } - - IceWall.removeDeadInstances(); - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public String getName() { - return "IceWall"; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Water.IceWall.Description"); - } - - public int getRange() { - return range; - } - - public void setRange(int range) { - this.range = range; - } - - public int getMaxHealth() { - return maxHealth; - } - - public void setMaxHealth(int maxHealth) { - this.maxHealth = maxHealth; - } - - public int getMinHealth() { - return minHealth; - } - - public void setMinHealth(int minHealth) { - this.minHealth = minHealth; - } - - public double getDamage() { - return damage; - } - - public void setDamage(double damage) { - this.damage = damage; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public boolean isRising() { - return rising; - } - - public void setRising(boolean rising) { - this.rising = rising; - } - - public long getLastDamageTime() { - return lastDamageTime; - } - - public void setLastDamageTime(long lastDamageTime) { - this.lastDamageTime = lastDamageTime; - } - - public long getLifetime() { - return lifetime; - } - - public void setLifetime(long lifetime) { - this.lifetime = lifetime; - } - - public int getWallHealth() { - return wallHealth; - } - - public void setWallHealth(int wallHealth) { - this.wallHealth = wallHealth; - } - - public int getTankedDamage() { - return tankedDamage; - } - - public void setTankedDamage(int tankedDamage) { - this.tankedDamage = tankedDamage; - } - - public List getLastBlocks() { - return lastBlocks; - } - - public List getTempBlocks() { - return tempBlocks; - } - - public int getMaxHeight() { - return maxHeight; - } - - public void setMaxHeight(int maxHeight) { - this.maxHeight = maxHeight; - } - - public int getMinHeight() { - return minHeight; - } - - public void setMinHeight(int minHeight) { - this.minHeight = minHeight; - } +public class IceWall extends IceAbility implements AddonAbility { + public static List instances = new ArrayList<>(); + + @Attribute(Attribute.HEIGHT) + private int maxHeight; + private int minHeight; + + @Attribute(Attribute.WIDTH) + private int width; + + @Attribute(Attribute.RANGE) + private int range; + + @Attribute("Health") + private int maxHealth; + private int minHealth; + + @Attribute(Attribute.DAMAGE) + private double damage; + + @Attribute(Attribute.COOLDOWN) + private long cooldown; + + public static boolean stackable; + + public static boolean lifetimeEnabled; + public static long lifetimeTime; + + public int torrentDamage; + public int torrentFreezeDamage; + public int iceBlastDamage; + public int fireBlastDamage; + public int fireBlastChargedDamage; + public int lightningDamage; + public int combustionDamage; + public int earthSmashDamage; + public int airBlastDamage; + + public boolean isWallDoneFor = false; + public List affectedBlocks = new ArrayList<>(); + + private boolean rising = false; + private long lastDamageTime = 0; + private long lifetime = 0; + private int wallHealth; + private int tankedDamage; + + private final List lastBlocks = new ArrayList<>(); + private final List tempBlocks = new ArrayList<>(); + + Random rand = new Random(); + + public IceWall(Player player) { + super(player); + if (!bPlayer.canBendIgnoreCooldowns(this) || !bPlayer.canIcebend()) { + return; + } + + setFields(); + Block b = getSourceBlock(player, (int) (range * getNightFactor(player.getWorld()))); + if (b == null) return; + + for (IceWall iw : instances) { + if (iw.affectedBlocks.contains(b)) { + iw.collapse(player, false); + return; + } + } + + if (!bPlayer.canBend(this) || !isWaterbendable(b)) return; + + wallHealth = (int) (((rand.nextInt((maxHealth - minHealth) + 1)) + minHealth) * getNightFactor(player.getWorld())); + loadAffectedBlocks(player, b); + lifetime = System.currentTimeMillis() + lifetimeTime; + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + maxHeight = (config.getInt("Abilities.Water.IceWall.MaxHeight")); + minHeight = (config.getInt("Abilities.Water.IceWall.MinHeight")); + width = (config.getInt("Abilities.Water.IceWall.Width")); + range = config.getInt("Abilities.Water.IceWall.Range"); + maxHealth = config.getInt("Abilities.Water.IceWall.MaxWallHealth"); + minHealth = config.getInt("Abilities.Water.IceWall.MinWallHealth"); + damage = config.getDouble("Abilities.Water.IceWall.Damage"); + cooldown = config.getLong("Abilities.Water.IceWall.Cooldown"); + stackable = config.getBoolean("Abilities.Water.IceWall.Stackable"); + lifetimeEnabled = config.getBoolean("Abilities.Water.IceWall.LifeTime.Enabled"); + lifetimeTime = config.getLong("Abilities.Water.IceWall.LifeTime.Duration"); + torrentDamage = config.getInt("Abilities.Water.IceWall.WallDamage.Torrent"); + torrentFreezeDamage = config.getInt("Abilities.Water.IceWall.WallDamage.TorrentFreeze"); + iceBlastDamage = config.getInt("Abilities.Water.IceWall.WallDamage.IceBlast"); + fireBlastDamage = config.getInt("Abilities.Water.IceWall.WallDamage.Fireblast"); + fireBlastChargedDamage = config.getInt("Abilities.Water.IceWall.WallDamage.FireblastCharged"); + lightningDamage = config.getInt("Abilities.Water.IceWall.WallDamage.Lightning"); + combustionDamage = config.getInt("Abilities.Water.IceWall.WallDamage.Combustion"); + earthSmashDamage = config.getInt("Abilities.Water.IceWall.WallDamage.EarthSmash"); + airBlastDamage = config.getInt("Abilities.Water.IceWall.WallDamage.AirBlast"); + } + + public Block getSourceBlock(Player player, int range) { + Vector direction = player.getEyeLocation().getDirection().normalize(); + + for (int i = 0; i <= range; i++) { + Block b = player.getEyeLocation().add(direction.clone().multiply((double) i)).getBlock(); + + if (isBendable(b)) return b; + } + + return null; + } + + public boolean isBendable(Block b) { + return isWater(b) || isIce(b.getType()) || isSnow(b.getType()); + } + + public void loadAffectedBlocks(Player player, Block block) { + Vector direction = player.getEyeLocation().getDirection().normalize(); + + double ox, oy, oz; + ox = -direction.getZ(); + oy = 0; + oz = direction.getX(); + + Vector orth = new Vector(ox, oy, oz); + orth = orth.normalize(); + + Location origin = block.getLocation(); + + World world = origin.getWorld(); + + int width = (int) (getWidth() * getNightFactor(world)); + int minHeight = (int) (getMinHeight() * getNightFactor(world)); + int maxHeight = (int) (getMaxHeight() * getNightFactor(world)); + + int height = minHeight; + boolean increasingHeight = true; + for (int i = -(width / 2); i < width / 2; i++) { + Block b = world.getBlockAt(origin.clone().add(orth.clone().multiply((double) i))); + + if (ElementalAbility.isAir(b.getType())) { + while (ElementalAbility.isAir(b.getType())) { + if (b.getY() < world.getMinHeight()) + return; + + b = b.getRelative(BlockFace.DOWN); + } + } + + if (!ElementalAbility.isAir(b.getRelative(BlockFace.UP).getType())) { + while (!ElementalAbility.isAir(b.getRelative(BlockFace.UP).getType())) { + if (b.getY() > b.getWorld().getMaxHeight()) + return; + + b = b.getRelative(BlockFace.UP); + } + } + + if (!stackable && isIceWallBlock(b)) { + continue; + } + + if (isBendable(b)) { + affectedBlocks.add(b); + for (int h = 1; h <= height; h++) { + Block up = b.getRelative(BlockFace.UP, h); + if (ElementalAbility.isAir(up.getType())) { + affectedBlocks.add(up); + } + } + + if (height < maxHeight && increasingHeight) + height++; + + if (i == 0) + increasingHeight = false; + + if (!increasingHeight && height > minHeight) + height--; + + lastBlocks.add(b); + } + + } + + bPlayer.addCooldown(this); + rising = true; + instances.add(this); + } + + @Override + public void progress() { + if (rising) { + if (lastBlocks.isEmpty()) { + rising = false; + } else { + List theseBlocks = new ArrayList<>(lastBlocks); + lastBlocks.clear(); + + for (Block b : theseBlocks) { + TempBlock tb = new TempBlock(b, Material.ICE.createBlockData()); + tempBlocks.add(tb); + + playIcebendingSound(b.getLocation()); + + Block up = b.getRelative(BlockFace.UP); + + if (affectedBlocks.contains(up)) + lastBlocks.add(up); + } + } + } + + if (System.currentTimeMillis() > lifetime && lifetimeEnabled) { + collapse(player, false); + } + } + + public void damageWall(Player player, int damage) { + long noDamageTicks = 1000; + if (System.currentTimeMillis() < lastDamageTime + noDamageTicks) + return; + + lastDamageTime = System.currentTimeMillis(); + tankedDamage += damage; + + if (tankedDamage >= wallHealth) { + collapse(player, true); + } + } + + public void collapse(Player player, boolean forceful) { + if (rising) return; + + for (TempBlock tb : tempBlocks) { + tb.revertBlock(); + tb.getLocation().getWorld().spawnParticle(Particle.BLOCK_CRACK, tb.getLocation(), 5, 0, 0, 0, 0, Material.PACKED_ICE.createBlockData()); + tb.getLocation().getWorld().playSound(tb.getLocation(), Sound.BLOCK_GLASS_BREAK, 5f, 5f); + + for (Entity e : GeneralMethods.getEntitiesAroundPoint(tb.getLocation(), 2.5)) { + if (e.getEntityId() != player.getEntityId() && e instanceof LivingEntity) { + DamageHandler.damageEntity(e, damage * getNightFactor(player.getWorld()), this); + if (forceful) { + ((LivingEntity) e).setNoDamageTicks(0); + } + } + } + } + + tempBlocks.clear(); + isWallDoneFor = true; + } + + @Override + public void remove() { + super.remove(); + } + + public static void collisionDamage(Entity entity, double travelledDistance, Vector difference, Player instigator) { + for (IceWall iw : IceWall.instances) { + for (Block b : iw.affectedBlocks) { + if (entity.getLocation().getWorld() == b.getLocation().getWorld() && entity.getLocation().distance(b.getLocation()) < 2) { + double damage = ((travelledDistance - 5.0) < 0 ? 0 : travelledDistance - 5.0) / (difference.length()); + iw.damageWall(instigator, (int) damage); + } + } + } + } + + public static boolean checkExplosions(Location location, Entity entity) { + for (IceWall iw : IceWall.instances) { + for (Block b : iw.affectedBlocks) { + if (location.getWorld() == b.getLocation().getWorld() && location.distance(b.getLocation()) < 2) { + + for (Entity e : GeneralMethods.getEntitiesAroundPoint(location, 3)) { + if (e instanceof LivingEntity) { + LivingEntity livingEntity = (LivingEntity) e; + ThreadUtil.ensureEntity(livingEntity, () -> livingEntity.damage(7, entity)); + } + } + return true; + } + } + } + return false; + } + + public static boolean isIceWallBlock(Block block) { + for (IceWall iw : IceWall.instances) { + if (iw.affectedBlocks.contains(block)) { + return true; + } + } + return false; + } + + public static void progressAll() { + for (IceWall iw : new ArrayList<>(instances)) { + if (iw.isWallDoneFor) continue; // Skip already collapsed walls + for (Torrent t : getAbilities(Torrent.class)) { + if (t.getLocation() == null) continue; + for (int i = 0; i < t.getLaunchedBlocks().size(); i++) { + TempBlock tb = t.getLaunchedBlocks().get(i); + + for (Block ice : iw.affectedBlocks) { + if (ice.getLocation().getWorld() == tb.getLocation().getWorld() && ice.getLocation().distance(tb.getLocation()) <= 2) { + if (t.isFreeze()) + iw.damageWall(t.getPlayer(), (int) (iw.torrentFreezeDamage * getNightFactor(ice.getWorld()))); + else + iw.damageWall(t.getPlayer(), (int) (iw.torrentDamage * getNightFactor(ice.getWorld()))); + + if (!iw.isWallDoneFor) + t.setFreeze(false); + } + } + } + } + + for (IceBlast ib : getAbilities(IceBlast.class)) { + if (ib.getLocation() == null) continue; + for (Block ice : iw.affectedBlocks) { + if (ib.source == null) + break; + + if (ice.getLocation().getWorld() == ib.source.getLocation().getWorld() && ice.getLocation().distance(ib.source.getLocation()) <= 2) { + iw.damageWall(ib.getPlayer(), (int) (iw.iceBlastDamage * getNightFactor(ice.getWorld()))); + + if (!iw.isWallDoneFor) + ib.remove(); + } + } + } + + for (FireBlastCharged fb : getAbilities(FireBlastCharged.class)) { + if (fb.getLocation() == null) continue; + for (Block ice : iw.affectedBlocks) { + if (ice.getLocation().getWorld() == fb.getLocation().getWorld() && fb.getLocation().distance(ice.getLocation()) <= 1.5) { + iw.damageWall(fb.getPlayer(), iw.fireBlastChargedDamage); + + if (!iw.isWallDoneFor) + fb.remove(); + } + } + } + + for (FireBlast fb : getAbilities(FireBlast.class)) { + if (fb.getLocation() == null) continue; + for (Block ice : iw.affectedBlocks) { + if (ice.getLocation().getWorld() == fb.getLocation().getWorld() && fb.getLocation().distance(ice.getLocation()) <= 1.5) { + iw.damageWall(fb.getPlayer(), iw.fireBlastDamage); + + if (!iw.isWallDoneFor) + fb.remove(); + } + } + } + + for (EarthSmash es : getAbilities(EarthSmash.class)) { + if (es.getLocation() == null) continue; + for (Block ice : iw.affectedBlocks) { + if (es.getState() == EarthSmash.State.SHOT) { + for (int j = 0; j < es.getBlocks().size(); j++) { + Block b = es.getBlocks().get(j); + if (ice.getLocation().getWorld() == b.getLocation().getWorld() && b.getLocation().distance(ice.getLocation()) <= 2) { + iw.damageWall(es.getPlayer(), iw.earthSmashDamage); + + if (!iw.isWallDoneFor) { + for (Block block : es.getBlocksIncludingInner()) { + if (block != null && !ElementalAbility.isAir(block.getType())) { + ParticleEffect.BLOCK_CRACK.display(block.getLocation(), 5, 0, 0, 0, 0, block.getBlockData().clone()); + } + } + es.remove(); + } + } + } + } + } + } + + for (Lightning l : getAbilities(Lightning.class)) { + for (Lightning.Arc arc : l.getArcs()) { + for (Block ice : iw.affectedBlocks) { + for (Location loc : arc.getPoints()) { + if (ice.getLocation().getWorld() == loc.getWorld() && loc.distance(ice.getLocation()) <= 1.5) { + iw.damageWall(l.getPlayer(), (int) (FireAbility.getDayFactor(iw.lightningDamage, ice.getWorld()))); + + if (!iw.isWallDoneFor) + l.remove(); + } + } + } + } + } + + for (CoreAbility ca : getAbilities(getAbility("Combustion").getClass())) { + if (ca.getLocation() == null) continue; + for (Block ice : iw.affectedBlocks) { + if (ice.getLocation().getWorld() == ca.getLocation().getWorld() && ca.getLocation().distance(ice.getLocation()) <= 1.5) { + iw.damageWall(ca.getPlayer(), iw.combustionDamage); + if (!iw.isWallDoneFor) ca.remove(); + } + } + } + } + + Iterator it = instances.iterator(); + while (it.hasNext()) { + IceWall iw = it.next(); + if (iw.isWallDoneFor) { + iw.affectedBlocks.clear(); + it.remove(); + } + } + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getName() { + return "IceWall"; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Water.IceWall.Description"); + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public int getMaxHealth() { + return maxHealth; + } + + public void setMaxHealth(int maxHealth) { + this.maxHealth = maxHealth; + } + + public int getMinHealth() { + return minHealth; + } + + public void setMinHealth(int minHealth) { + this.minHealth = minHealth; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public boolean isRising() { + return rising; + } + + public void setRising(boolean rising) { + this.rising = rising; + } + + public long getLastDamageTime() { + return lastDamageTime; + } + + public void setLastDamageTime(long lastDamageTime) { + this.lastDamageTime = lastDamageTime; + } + + public long getLifetime() { + return lifetime; + } + + public void setLifetime(long lifetime) { + this.lifetime = lifetime; + } + + public int getWallHealth() { + return wallHealth; + } + + public void setWallHealth(int wallHealth) { + this.wallHealth = wallHealth; + } + + public int getTankedDamage() { + return tankedDamage; + } + + public void setTankedDamage(int tankedDamage) { + this.tankedDamage = tankedDamage; + } + + public List getLastBlocks() { + return lastBlocks; + } + + public List getTempBlocks() { + return tempBlocks; + } + + public int getMaxHeight() { + return maxHeight; + } + + public void setMaxHeight(int maxHeight) { + this.maxHeight = maxHeight; + } + + public int getMinHeight() { + return minHeight; + } + + public void setMinHeight(int minHeight) { + this.minHeight = minHeight; + } - public int getWidth() { - return width; - } + public int getWidth() { + return width; + } - public void setWidth(int width) { - this.width = width; - } + public void setWidth(int width) { + this.width = width; + } - @Override - public void load() {} + @Override + public void load() {} - @Override - public void stop() {} + @Override + public void stop() {} - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Water.IceWall.Enabled"); - } -} + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Water.IceWall.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/WakeFishing.java b/src/com/jedk1/jedcore/ability/waterbending/WakeFishing.java index 6f4bf55..9d746ac 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/WakeFishing.java +++ b/src/com/jedk1/jedcore/ability/waterbending/WakeFishing.java @@ -8,7 +8,6 @@ import com.projectkorra.projectkorra.util.BlockSource; import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.ParticleEffect; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -24,214 +23,213 @@ public class WakeFishing extends WaterAbility implements AddonAbility { - private final static Material[] FISH_TYPES = { - Material.COD, Material.PUFFERFISH, Material.TROPICAL_FISH, Material.SALMON - }; - - private Block focusedBlock; - private Location location; - private int point; - - @Attribute(Attribute.COOLDOWN) - private long cooldown; - @Attribute(Attribute.DURATION) - private long duration; - @Attribute(Attribute.RANGE) - private long range; - - Random rand = new Random(); - - public WakeFishing(Player player) { - super(player); - if (!bPlayer.canBend(this)) { - return; - } - - setFields(); - - if (prepare()) - start(); - } - - public void setFields() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - - cooldown = config.getLong("Abilities.Water.WakeFishing.Cooldown"); - duration = config.getLong("Abilities.Water.WakeFishing.Duration"); - range = config.getLong("Abilities.Water.WakeFishing.Range"); - - applyModifiers(); - } - - private void applyModifiers() { - if (isNight(player.getWorld())) { - cooldown -= ((long) getNightFactor(cooldown) - cooldown); - range = (long) getNightFactor(range); - } - } - - @SuppressWarnings("deprecation") - private boolean prepare() { - Block block = BlockSource.getWaterSourceBlock(player, range, ClickType.SHIFT_DOWN, true, false, false); - if (isWater(block) && block.getData() == 0) { - focusedBlock = block; - location = focusedBlock.getLocation(); - return true; - } - return false; - } - - private boolean isFocused() { - Block block = BlockSource.getWaterSourceBlock(player, range, ClickType.SHIFT_DOWN, true, false, false); - return block != null && block.equals(focusedBlock); - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline() || !player.isSneaking()) { - remove(); - return; - } - if (!bPlayer.canBendIgnoreCooldowns(this) || !isFocused()) { - bPlayer.addCooldown(this); - remove(); - return; - } - if (System.currentTimeMillis() > getStartTime() + duration) { - bPlayer.addCooldown(this); - remove(); - return; - } - displayParticles(); - spawnFishRandom(); - } - - private void displayParticles() { - point++; - if (point == 32) - point = 0; - for (int i = 0; i < 4; i++) { - ParticleEffect.WATER_SPLASH.display(getCirclePoints(focusedBlock.getLocation().clone().add(0.5, 0, 0.5), 32, (i * 90), 1).get(point), 3, 0, 0, 0, 0.05); - ParticleEffect.WATER_WAKE.display(getCirclePoints(focusedBlock.getLocation().clone().add(0.5, -0.6, 0.5), 32, (i * 90), 1).get(point), 1, 0, 0, 0, 0.02); - } - - ParticleEffect.SMOKE_NORMAL.display(focusedBlock.getLocation().clone().add(.5, .5, .5), 2, 0, 0, 0, 0.001); - } - - private void spawnFishRandom() { - if (rand.nextInt(50) == 0) { - Material fishType = FISH_TYPES[rand.nextInt(FISH_TYPES.length)]; - ItemStack fish = new ItemStack(fishType, 1); - - Item item = player.getWorld().dropItemNaturally(focusedBlock.getLocation().clone().add(.5, 1.5, .5), fish); - Vector v = player.getEyeLocation().toVector().subtract(focusedBlock.getLocation().clone().add(.5, 1.5, .5).toVector()); - item.setVelocity(v.multiply(.15)); - } - } - - private List getCirclePoints(Location location, int points, int startAngle, double size) { - List locations = new ArrayList(); - for (int i = 0; i < 360; i += 360 / points) { - double angle = (i * Math.PI / 180); - double x = size * Math.cos(angle + startAngle); - double z = size * Math.sin(angle + startAngle); - Location loc = location.clone(); - loc.add(x, 1, z); - locations.add(loc); - } - return locations; - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public String getName() { - return "WakeFishing"; - } - - @Override - public boolean isHarmlessAbility() { - return true; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return "* JedCore Addon *\n" + config.getString("Abilities.Water.WakeFishing.Description"); - } - - public Block getFocusedBlock() { - return focusedBlock; - } - - public void setFocusedBlock(Block focusedBlock) { - this.focusedBlock = focusedBlock; - } - - public void setLocation(Location location) { - this.location = location; - } - - public int getPoint() { - return point; - } - - public void setPoint(int point) { - this.point = point; - } - - public void setCooldown(long cooldown) { - this.cooldown = cooldown; - } - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - public long getRange() { - return range; - } - - public void setRange(long range) { - this.range = range; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - ConfigurationSection config = JedCoreConfig.getConfig(this.player); - return config.getBoolean("Abilities.Water.WakeFishing.Enabled"); - } -} + private final static Material[] FISH_TYPES = { + Material.COD, Material.PUFFERFISH, Material.TROPICAL_FISH, Material.SALMON + }; + + private Block focusedBlock; + private Location location; + private int point; + + @Attribute(Attribute.COOLDOWN) + private long cooldown; + @Attribute(Attribute.DURATION) + private long duration; + @Attribute(Attribute.RANGE) + private long range; + + Random rand = new Random(); + + public WakeFishing(Player player) { + super(player); + if (!bPlayer.canBend(this)) { + return; + } + + setFields(); + + if (prepare()) + start(); + } + + public void setFields() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + + cooldown = config.getLong("Abilities.Water.WakeFishing.Cooldown"); + duration = config.getLong("Abilities.Water.WakeFishing.Duration"); + range = config.getLong("Abilities.Water.WakeFishing.Range"); + + applyModifiers(); + } + + private void applyModifiers() { + if (isNight(player.getWorld())) { + cooldown -= ((long) getNightFactor(cooldown) - cooldown); + range = (long) getNightFactor(range); + } + } + + private boolean prepare() { + Block block = BlockSource.getWaterSourceBlock(player, range, ClickType.SHIFT_DOWN, true, false, false); + if (isWater(block)) { + focusedBlock = block; + location = focusedBlock.getLocation(); + return true; + } + return false; + } + + private boolean isFocused() { + Block block = BlockSource.getWaterSourceBlock(player, range, ClickType.SHIFT_DOWN, true, false, false); + return block != null && block.equals(focusedBlock); + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline() || !player.isSneaking()) { + remove(); + return; + } + if (!bPlayer.canBendIgnoreCooldowns(this) || !isFocused()) { + bPlayer.addCooldown(this); + remove(); + return; + } + if (System.currentTimeMillis() > getStartTime() + duration) { + bPlayer.addCooldown(this); + remove(); + return; + } + displayParticles(); + spawnFishRandom(); + } + + private void displayParticles() { + point++; + if (point == 32) + point = 0; + for (int i = 0; i < 4; i++) { + ParticleEffect.WATER_SPLASH.display(getCirclePoints(focusedBlock.getLocation().clone().add(0.5, 0, 0.5), 32, (i * 90), 1).get(point), 3, 0, 0, 0, 0.05); + ParticleEffect.WATER_WAKE.display(getCirclePoints(focusedBlock.getLocation().clone().add(0.5, -0.6, 0.5), 32, (i * 90), 1).get(point), 1, 0, 0, 0, 0.02); + } + + ParticleEffect.SMOKE_NORMAL.display(focusedBlock.getLocation().clone().add(.5, .5, .5), 2, 0, 0, 0, 0.001); + } + + private void spawnFishRandom() { + if (rand.nextInt(50) == 0) { + Material fishType = FISH_TYPES[rand.nextInt(FISH_TYPES.length)]; + ItemStack fish = new ItemStack(fishType, 1); + + Item item = player.getWorld().dropItemNaturally(focusedBlock.getLocation().clone().add(.5, 1.5, .5), fish); + Vector v = player.getEyeLocation().toVector().subtract(focusedBlock.getLocation().clone().add(.5, 1.5, .5).toVector()); + item.setVelocity(v.multiply(.15)); + } + } + + private List getCirclePoints(Location location, int points, int startAngle, double size) { + List locations = new ArrayList(); + for (int i = 0; i < 360; i += 360 / points) { + double angle = (i * Math.PI / 180); + double x = size * Math.cos(angle + startAngle); + double z = size * Math.sin(angle + startAngle); + Location loc = location.clone(); + loc.add(x, 1, z); + locations.add(loc); + } + return locations; + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getName() { + return "WakeFishing"; + } + + @Override + public boolean isHarmlessAbility() { + return true; + } + + @Override + public boolean isSneakAbility() { + return true; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return "* JedCore Addon *\n" + config.getString("Abilities.Water.WakeFishing.Description"); + } + + public Block getFocusedBlock() { + return focusedBlock; + } + + public void setFocusedBlock(Block focusedBlock) { + this.focusedBlock = focusedBlock; + } + + public void setLocation(Location location) { + this.location = location; + } + + public int getPoint() { + return point; + } + + public void setPoint(int point) { + this.point = point; + } + + public void setCooldown(long cooldown) { + this.cooldown = cooldown; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public long getRange() { + return range; + } + + public void setRange(long range) { + this.range = range; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + ConfigurationSection config = JedCoreConfig.getConfig(this.player); + return config.getBoolean("Abilities.Water.WakeFishing.Enabled"); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/WaterBlast.java b/src/com/jedk1/jedcore/ability/waterbending/WaterBlast.java index 44d4266..c459181 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/WaterBlast.java +++ b/src/com/jedk1/jedcore/ability/waterbending/WaterBlast.java @@ -12,7 +12,6 @@ import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.BlockFace; @@ -22,224 +21,224 @@ public class WaterBlast extends WaterAbility implements AddonAbility { - private Location location; - private Vector direction; - private final Ability ability; - private double travelled; - - @Attribute(Attribute.RANGE) - private final double range; - @Attribute(Attribute.DAMAGE) - private final double damage; - @Attribute(Attribute.SPEED) - private final double speed; - @Attribute("CollisionRadius") - private final double entityCollisionRadius; - @Attribute("CollisionRadius") - private final double abilityCollisionRadius; - - static { - CollisionInitializer.abilityMap.put("WaterBlast", "WaterGimbal"); - } - - public WaterBlast(Player player, Location origin, double range, double damage, double speed, double entityCollisionRadius, double abilityCollisionRadius, Ability ability) { - super(player); - - this.range = range; - this.damage = damage; - this.speed = speed; - this.ability = ability; - this.location = origin; - this.entityCollisionRadius = entityCollisionRadius; - this.abilityCollisionRadius = abilityCollisionRadius; - - start(); - } - - @Override - public void progress() { - if (player.isDead() || !player.isOnline()) { - remove(); - return; - } - - if (travelled >= range) { - remove(); - return; - } - - if (!advanceAttack()) { - remove(); - } - } - - private boolean advanceAttack() { - int steps = (int)Math.ceil(speed); - // This is how much the last step should move by. - double remainder = speed - Math.floor(speed); - - // Move in discrete steps so each block can be checked for collisions. - for (int i = 0; i < steps; i++) { - double stepSpeed = 1.0; - - if (remainder > 0 && i == steps - 1) { - // The last step should only move by the remainder because there are Math.ceil(speed) steps. - stepSpeed = remainder; - } - - travelled += stepSpeed; - - if (travelled >= range) { - return false; - } - - if (!player.isDead()) { - Location target = GeneralMethods.getTargetedLocation(player, range, Material.WATER); - if (location.distanceSquared(target) <= 1) { - // Make sure the WaterBlast moves in to the solid block. - target = target.add(player.getLocation().getDirection()); - } - direction = GeneralMethods.getDirection(location, target).normalize(); - } - - location = location.add(direction.clone().multiply(stepSpeed)); - - if (GeneralMethods.isSolid(location.getBlock())) { - if (!GeneralMethods.isSolid(location.getBlock().getRelative(BlockFace.UP))) { - location.add(0, 1, 0); - } else { - return false; - } - } - - if (!isTransparent(location.getBlock()) || RegionProtection.isRegionProtected(this, location)) { - return false; - } - - playWaterbendingSound(location); - - new RegenTempBlock(location.getBlock(), Material.WATER, Material.WATER.createBlockData(bd -> ((Levelled)bd).setLevel(0)), 250); - - // Only damage entities that are more than 3 blocks away. - if (travelled >= 3) { - AABB collider = AABB.BlockBounds.at(location).scale(entityCollisionRadius * 2); - - boolean hit = CollisionDetector.checkEntityCollisions(player, collider, (entity) -> { - DamageHandler.damageEntity(entity, damage, ability); - return true; - }); - - if (hit) { - return false; - } - } - } - - return true; - } - - @Override - public long getCooldown() { - return 0; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public double getCollisionRadius() { - return abilityCollisionRadius; - } - - @Override - public String getName() { - return "WaterBlast"; - } - - @Override - public boolean isHiddenAbility() { - return true; - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return false; - } - - @Override - public String getAuthor() { - return JedCore.dev; - } - - @Override - public String getVersion() { - return JedCore.version; - } - - @Override - public String getDescription() { - return null; - } - - public void setLocation(Location location) { - this.location = location; - } - - public Vector getDirection() { - return direction; - } - - public void setDirection(Vector direction) { - this.direction = direction; - } - - public Ability getAbility() { - return ability; - } - - public double getTravelled() { - return travelled; - } - - public void setTravelled(double travelled) { - this.travelled = travelled; - } - - public double getRange() { - return range; - } - - public double getDamage() { - return damage; - } - - public double getSpeed() { - return speed; - } - - public double getEntityCollisionRadius() { - return entityCollisionRadius; - } - - public double getAbilityCollisionRadius() { - return abilityCollisionRadius; - } - - @Override - public void load() {} - - @Override - public void stop() {} - - @Override - public boolean isEnabled() { - return true; - } -} + private Location location; + private Vector direction; + private final Ability ability; + private double travelled; + + @Attribute(Attribute.RANGE) + private final double range; + @Attribute(Attribute.DAMAGE) + private final double damage; + @Attribute(Attribute.SPEED) + private final double speed; + @Attribute("CollisionRadius") + private final double entityCollisionRadius; + @Attribute("CollisionRadius") + private final double abilityCollisionRadius; + + static { + CollisionInitializer.abilityMap.put("WaterBlast", "WaterGimbal"); + } + + public WaterBlast(Player player, Location origin, double range, double damage, double speed, double entityCollisionRadius, double abilityCollisionRadius, Ability ability) { + super(player); + + this.range = range; + this.damage = damage; + this.speed = speed; + this.ability = ability; + this.location = origin; + this.entityCollisionRadius = entityCollisionRadius; + this.abilityCollisionRadius = abilityCollisionRadius; + + start(); + } + + @Override + public void progress() { + if (player.isDead() || !player.isOnline()) { + remove(); + return; + } + + if (travelled >= range) { + remove(); + return; + } + + if (!advanceAttack()) { + remove(); + } + } + + private boolean advanceAttack() { + int steps = (int)Math.ceil(speed); + // This is how much the last step should move by. + double remainder = speed - Math.floor(speed); + + // Move in discrete steps so each block can be checked for collisions. + for (int i = 0; i < steps; i++) { + double stepSpeed = 1.0; + + if (remainder > 0 && i == steps - 1) { + // The last step should only move by the remainder because there are Math.ceil(speed) steps. + stepSpeed = remainder; + } + + travelled += stepSpeed; + + if (travelled >= range) { + return false; + } + + if (!player.isDead()) { + Location target = GeneralMethods.getTargetedLocation(player, range, Material.WATER); + if (location.distanceSquared(target) <= 1) { + // Make sure the WaterBlast moves in to the solid block. + target = target.add(player.getLocation().getDirection()); + } + direction = GeneralMethods.getDirection(location, target).normalize(); + } + + location = location.add(direction.clone().multiply(stepSpeed)); + + if (GeneralMethods.isSolid(location.getBlock())) { + if (!GeneralMethods.isSolid(location.getBlock().getRelative(BlockFace.UP))) { + location.add(0, 1, 0); + } else { + return false; + } + } + + if (!isTransparent(location.getBlock()) || RegionProtection.isRegionProtected(this, location)) { + return false; + } + + playWaterbendingSound(location); + + new RegenTempBlock(location.getBlock(), Material.WATER, Material.WATER.createBlockData(bd -> ((Levelled)bd).setLevel(0)), 250); + + // Only damage entities that are more than 3 blocks away. + if (travelled >= 3) { + AABB collider = AABB.BlockBounds.at(location).scale(entityCollisionRadius * 2); + + boolean hit = CollisionDetector.checkEntityCollisions(player, collider, (entity) -> { + DamageHandler.damageEntity(entity, damage, ability); + return true; + }); + + if (hit) { + return false; + } + } + } + + return true; + } + + @Override + public long getCooldown() { + return 0; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public double getCollisionRadius() { + return abilityCollisionRadius; + } + + @Override + public String getName() { + return "WaterBlast"; + } + + @Override + public boolean isHiddenAbility() { + return true; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public boolean isSneakAbility() { + return false; + } + + @Override + public String getAuthor() { + return JedCore.dev; + } + + @Override + public String getVersion() { + return JedCore.version; + } + + @Override + public String getDescription() { + return null; + } + + public void setLocation(Location location) { + this.location = location; + } + + public Vector getDirection() { + return direction; + } + + public void setDirection(Vector direction) { + this.direction = direction; + } + + public Ability getAbility() { + return ability; + } + + public double getTravelled() { + return travelled; + } + + public void setTravelled(double travelled) { + this.travelled = travelled; + } + + public double getRange() { + return range; + } + + public double getDamage() { + return damage; + } + + public double getSpeed() { + return speed; + } + + public double getEntityCollisionRadius() { + return entityCollisionRadius; + } + + public double getAbilityCollisionRadius() { + return abilityCollisionRadius; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public boolean isEnabled() { + return true; + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/ability/waterbending/combo/Maelstrom.java b/src/com/jedk1/jedcore/ability/waterbending/combo/Maelstrom.java index ec02664..b394f55 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/combo/Maelstrom.java +++ b/src/com/jedk1/jedcore/ability/waterbending/combo/Maelstrom.java @@ -14,7 +14,6 @@ import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.waterbending.Torrent; - import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -249,12 +248,13 @@ public Object createNewComboInstance(Player player) { return new Maelstrom(player); } - @Override - public ArrayList getCombination() { - return ComboUtil.generateCombinationFromList(this, JedCoreConfig.getConfig(player).getStringList("Abilities.Water.WaterCombo.Maelstrom.Combination")); - } + @Override + public ArrayList getCombination() { + return ComboUtil.generateCombinationFromList(this, JedCoreConfig.getConfig(player).getStringList("Abilities.Water.WaterCombo.Maelstrom.Combination")); + } - @Override + + @Override public String getInstructions() { return JedCoreConfig.getConfig(player).getString("Abilities.Water.WaterCombo.Maelstrom.Instructions"); } diff --git a/src/com/jedk1/jedcore/ability/waterbending/combo/WaterFlow.java b/src/com/jedk1/jedcore/ability/waterbending/combo/WaterFlow.java index ee9c1f8..c1adb24 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/combo/WaterFlow.java +++ b/src/com/jedk1/jedcore/ability/waterbending/combo/WaterFlow.java @@ -6,7 +6,10 @@ import com.jedk1.jedcore.util.MaterialUtil; import com.jedk1.jedcore.util.RegenTempBlock; import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.*; +import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.ComboAbility; +import com.projectkorra.projectkorra.ability.WaterAbility; import com.projectkorra.projectkorra.ability.util.ComboManager.AbilityInformation; import com.projectkorra.projectkorra.ability.util.ComboUtil; import com.projectkorra.projectkorra.airbending.AirSpout; @@ -19,7 +22,6 @@ import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.waterbending.WaterManipulation; import com.projectkorra.projectkorra.waterbending.WaterSpout; - import com.projectkorra.projectkorra.waterbending.plant.PlantRegrowth; import com.projectkorra.projectkorra.waterbending.util.WaterReturn; import org.bukkit.Location; diff --git a/src/com/jedk1/jedcore/ability/waterbending/combo/WaterGimbal.java b/src/com/jedk1/jedcore/ability/waterbending/combo/WaterGimbal.java index 6fe64ca..9fed934 100644 --- a/src/com/jedk1/jedcore/ability/waterbending/combo/WaterGimbal.java +++ b/src/com/jedk1/jedcore/ability/waterbending/combo/WaterGimbal.java @@ -17,9 +17,8 @@ import com.projectkorra.projectkorra.util.BlockSource; import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.TempBlock; -import com.projectkorra.projectkorra.waterbending.WaterManipulation; import com.projectkorra.projectkorra.waterbending.Torrent; - +import com.projectkorra.projectkorra.waterbending.WaterManipulation; import com.projectkorra.projectkorra.waterbending.ice.PhaseChange; import com.projectkorra.projectkorra.waterbending.plant.PlantRegrowth; import com.projectkorra.projectkorra.waterbending.util.WaterReturn; diff --git a/src/com/jedk1/jedcore/collision/AABB.java b/src/com/jedk1/jedcore/collision/AABB.java index 35df188..a32398e 100644 --- a/src/com/jedk1/jedcore/collision/AABB.java +++ b/src/com/jedk1/jedcore/collision/AABB.java @@ -180,4 +180,4 @@ private Vector max(Block block) { return worldMax.clone().subtract(block.getLocation().toVector()); } -} +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/collision/Collider.java b/src/com/jedk1/jedcore/collision/Collider.java index 03cedca..5b15d49 100644 --- a/src/com/jedk1/jedcore/collision/Collider.java +++ b/src/com/jedk1/jedcore/collision/Collider.java @@ -9,4 +9,4 @@ public interface Collider { Vector getHalfExtents(); boolean contains(Vector point); -} +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/collision/CollisionDetector.java b/src/com/jedk1/jedcore/collision/CollisionDetector.java index 8ff839a..457dee4 100644 --- a/src/com/jedk1/jedcore/collision/CollisionDetector.java +++ b/src/com/jedk1/jedcore/collision/CollisionDetector.java @@ -12,7 +12,9 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.*; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; public class CollisionDetector { public static boolean checkEntityCollisions(Player player, Collider collider, CollisionCallback function) { @@ -122,4 +124,4 @@ public interface CollisionCallback { // return true to break out of the loop boolean onCollision(Entity e); } -} +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/collision/CollisionUtil.java b/src/com/jedk1/jedcore/collision/CollisionUtil.java index 1095edf..caad776 100644 --- a/src/com/jedk1/jedcore/collision/CollisionUtil.java +++ b/src/com/jedk1/jedcore/collision/CollisionUtil.java @@ -31,4 +31,4 @@ public static void handleFallingBlockCollisions(Collision collision, List args) { - if (!isPlayer(sender) || !correctLength(sender, args.size(), 0, 0) || !hasPermission(sender)) { - return; - } - if (args.size() == 0) { - BendingBoard.toggle((Player) sender); - } else { - help(sender, false); - } - } -} diff --git a/src/com/jedk1/jedcore/command/Commands.java b/src/com/jedk1/jedcore/command/Commands.java index 0ac6876..1c23a38 100644 --- a/src/com/jedk1/jedcore/command/Commands.java +++ b/src/com/jedk1/jedcore/command/Commands.java @@ -1,14 +1,9 @@ package com.jedk1.jedcore.command; -import com.jedk1.jedcore.scoreboard.BendingBoard; - public class Commands { public Commands() { - if (BendingBoard.enabled) { - new BoardCommand(); - } new JedCoreCommand(); } } diff --git a/src/com/jedk1/jedcore/command/JedCoreCommand.java b/src/com/jedk1/jedcore/command/JedCoreCommand.java index f2534ca..0e994f3 100644 --- a/src/com/jedk1/jedcore/command/JedCoreCommand.java +++ b/src/com/jedk1/jedcore/command/JedCoreCommand.java @@ -1,21 +1,29 @@ package com.jedk1.jedcore.command; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; - +import com.jedk1.jedcore.JedCore; +import com.projectkorra.projectkorra.command.PKCommand; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import com.jedk1.jedcore.JedCore; -import com.projectkorra.projectkorra.command.PKCommand; +import java.util.List; +import java.util.Set; +import java.util.UUID; public class JedCoreCommand extends PKCommand { - private static final String DOWNLOAD_URL = "https://github.com/CozmycDev/JedCore"; + + private static final String DOWNLOAD_URL = "https://github.com/Hihelloy-main/JedCore"; + + private static final Set DEVELOPERS = Set.of( + UUID.fromString("4eb6315e-9dd1-49f7-b582-c1170e497ab0"), // jedk1 + UUID.fromString("d57565a5-e6b0-44e3-a026-979d5de10c4d"), // s3xi + UUID.fromString("e98a2f7d-d571-4900-a625-483cbe6774fe"), // Aztl + UUID.fromString("b1318b21-5956-445c-a328-bad3175c1c7a") // Hihelloy + ); public JedCoreCommand() { - super("jedcore", "/bending jedcore", "This command will show the statistics and version of JedCore.", new String[] { "jedcore", "jc" }); + super("jedcore", "/bending jedcore", "This command shows the JedCore version and debug info.", new String[] { "jedcore", "jc" }); } @Override @@ -23,37 +31,37 @@ public void execute(CommandSender sender, List args) { if (!correctLength(sender, args.size(), 0, 1) || (!hasPermission(sender) && !isSenderJedCoreDev(sender))) { return; } - if (args.size() == 0) { + if (isSenderJedCoreDev(sender) && sender instanceof Player) { + sender.sendMessage("Thanks for your contribution" + ((Player) sender).getUniqueId()); + } + + if (args.isEmpty()) { sendBuildInfo(sender); - } else if (args.size() == 1 && (hasPermission(sender, "debug") || isSenderJedCoreDev(sender))) { - //Dev commands for debugging etc. + return; + } + + if (args.size() == 1 && (hasPermission(sender, "debug") || isSenderJedCoreDev(sender))) { if (args.get(0).equalsIgnoreCase("refresh")) { - sender.sendMessage(ChatColor.AQUA + "Jedcore refreshed."); + sender.sendMessage(ChatColor.AQUA + "JedCore refreshed."); + return; } - } else { - help(sender, false); } + + help(sender, false); } public static void sendBuildInfo(CommandSender sender) { sender.sendMessage(ChatColor.GRAY + "Running JedCore Build: " + ChatColor.RED + JedCore.plugin.getDescription().getVersion()); - sender.sendMessage(ChatColor.GRAY + "Developed by: " + ChatColor.RED + JedCore.plugin.getDescription().getAuthors().toString().replace("[", "").replace("]", "")); + sender.sendMessage(ChatColor.GRAY + "Developed by: " + ChatColor.RED + String.join(", ", JedCore.plugin.getDescription().getAuthors())); sender.sendMessage(ChatColor.GRAY + "Modified by: " + ChatColor.RED + "plushmonkey"); sender.sendMessage(ChatColor.GRAY + "Maintained by: " + ChatColor.RED + "Cozmyc"); + sender.sendMessage(ChatColor.GRAY + "Updated by: " + ChatColor.RED + "Hihelloy"); sender.sendMessage(ChatColor.GRAY + "URL: " + ChatColor.RED + ChatColor.ITALIC + DOWNLOAD_URL); } - + private boolean isSenderJedCoreDev(CommandSender sender) { - UUID[] devs = { - UUID.fromString("4eb6315e-9dd1-49f7-b582-c1170e497ab0"), - UUID.fromString("d57565a5-e6b0-44e3-a026-979d5de10c4d"), - UUID.fromString("e98a2f7d-d571-4900-a625-483cbe6774fe") - }; - if (sender instanceof Player) { - Player player = (Player) sender; - if (Arrays.asList(devs).contains(player.getUniqueId())) { - return true; - } + if (sender instanceof Player player) { + return DEVELOPERS.contains(player.getUniqueId()); } return false; } diff --git a/src/com/jedk1/jedcore/configuration/Config.java b/src/com/jedk1/jedcore/configuration/Config.java index d4c427b..14aebfd 100644 --- a/src/com/jedk1/jedcore/configuration/Config.java +++ b/src/com/jedk1/jedcore/configuration/Config.java @@ -1,7 +1,6 @@ package com.jedk1.jedcore.configuration; import com.jedk1.jedcore.JedCore; - import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; diff --git a/src/com/jedk1/jedcore/configuration/JedCoreConfig.java b/src/com/jedk1/jedcore/configuration/JedCoreConfig.java index 4acc321..5ac523a 100644 --- a/src/com/jedk1/jedcore/configuration/JedCoreConfig.java +++ b/src/com/jedk1/jedcore/configuration/JedCoreConfig.java @@ -1,8 +1,6 @@ package com.jedk1.jedcore.configuration; import com.jedk1.jedcore.JedCore; - -import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.configuration.ConfigManager; import org.bukkit.Material; import org.bukkit.World; @@ -16,1043 +14,1091 @@ public class JedCoreConfig { - public static Config board; - static JedCore plugin; - - public JedCoreConfig(JedCore plugin) { - JedCoreConfig.plugin = plugin; - board = new Config(new File("board.yml")); - loadConfigBoard(); - loadConfigCore(); - addDeathMessages(); - setupElementSphereNames(); - } - - private void loadConfigBoard() { - FileConfiguration config; - config = board.getConfig(); - - config.addDefault("Settings.Enabled", true); - config.addDefault("Settings.Title", "&lSlots"); - config.addDefault("Settings.Pointer", "> "); - config.addDefault("Settings.EmptySlot", "&8&o-- Slot % --"); - config.addDefault("Settings.Combos", "&fCombos:"); - config.addDefault("Settings.Toggle.Off", "&7You have hidden the bending board."); - config.addDefault("Settings.Toggle.On", "&7You have toggled the bending board on."); - config.addDefault("Settings.Display.DisabledWorlds", true); - - config.addDefault("Settings.OtherCooldowns.WallRun.Color", "GOLD"); - config.addDefault("Settings.OtherCooldowns.WallRun.Enabled", true); - config.addDefault("Settings.OtherCooldowns.TorrentWave.Color", "AQUA"); - config.addDefault("Settings.OtherCooldowns.TorrentWave.Enabled", true); - config.addDefault("Settings.OtherCooldowns.SurgeWave.Color", "AQUA"); - config.addDefault("Settings.OtherCooldowns.SurgeWave.Enabled", true); - config.addDefault("Settings.OtherCooldowns.SurgeWall.Color", "AQUA"); - config.addDefault("Settings.OtherCooldowns.SurgeWall.Enabled", true); - config.addDefault("Settings.OtherCooldowns.RaiseEarthPillar.Color", "GREEN"); - config.addDefault("Settings.OtherCooldowns.RaiseEarthPillar.Enabled", true); - config.addDefault("Settings.OtherCooldowns.RaiseEarthWall.Color", "GREEN"); - config.addDefault("Settings.OtherCooldowns.RaiseEarthWall.Enabled", true); - - config.options().copyDefaults(true); - board.saveConfig(); - } - - private void loadConfigCore() { - FileConfiguration config; - config = JedCore.plugin.getConfig(); - - config.addDefault("Settings.Updater.Check", true); - config.addDefault("Settings.Updater.Notify", true); - config.addDefault("Properties.MobCollisions.Enabled", true); - config.addDefault("Properties.AbilityCollisions.Enabled", true); - config.addDefault("Properties.PerWorldConfig", true); - config.addDefault("Properties.FireTickMethod", "larger"); - config.addDefault("Properties.LogDebug", false); - - config.addDefault("Properties.ChiRestrictor.Enabled", false); - config.addDefault("Properties.ChiRestrictor.ResetCooldown", true); - config.addDefault("Properties.ChiRestrictor.MeleeDistance", 7); - config.addDefault("Properties.ChiRestrictor.Whitelist", new ArrayList()); - - config.addDefault("Properties.Fire.DynamicLight.Enabled", true); - config.addDefault("Properties.Fire.DynamicLight.Brightness", 13); - config.addDefault("Properties.Fire.DynamicLight.KeepAlive", 600); - - config.addDefault("Abilities.Avatar.ElementSphere.Enabled", true); - config.addDefault("Abilities.Avatar.ElementSphere.Description", "ElementSphere is a very all round ability, being " - + "able to shoot attacks of each element, each with a " - + "different affect. To use, simply Left-Click. Once active, " - + "Sneak (Default: Shift) to fly around. Sneak and double " - + "Left-Click to disable the ability! " - + "To use each element, simply select hotbar slots 1-4 and Left-Click. " - + "Each element has limited uses! Once an element is used up, " - + "the element's ring will disappear!"); - config.addDefault("Abilities.Avatar.ElementSphere.Cooldown", 180000); - config.addDefault("Abilities.Avatar.ElementSphere.Duration", 60000); - config.addDefault("Abilities.Avatar.ElementSphere.MaxControlledHeight", 40); - config.addDefault("Abilities.Avatar.ElementSphere.FlySpeed", 1.5); - config.addDefault("Abilities.Avatar.ElementSphere.Air.Cooldown", 500); - config.addDefault("Abilities.Avatar.ElementSphere.Air.Range", 40); - config.addDefault("Abilities.Avatar.ElementSphere.Air.Uses", 20); - config.addDefault("Abilities.Avatar.ElementSphere.Air.Damage", 3.0); - config.addDefault("Abilities.Avatar.ElementSphere.Air.Knockback", 2); - config.addDefault("Abilities.Avatar.ElementSphere.Air.Speed", 3); - config.addDefault("Abilities.Avatar.ElementSphere.Earth.Cooldown", 500); - config.addDefault("Abilities.Avatar.ElementSphere.Earth.Uses", 20); - config.addDefault("Abilities.Avatar.ElementSphere.Earth.Damage", 3.0); - config.addDefault("Abilities.Avatar.ElementSphere.Earth.ImpactCraterSize", 3); - config.addDefault("Abilities.Avatar.ElementSphere.Earth.ImpactRevert", 15000); - config.addDefault("Abilities.Avatar.ElementSphere.Fire.Cooldown", 500); - config.addDefault("Abilities.Avatar.ElementSphere.Fire.Range", 40); - config.addDefault("Abilities.Avatar.ElementSphere.Fire.Uses", 20); - config.addDefault("Abilities.Avatar.ElementSphere.Fire.Damage", 3.0); - config.addDefault("Abilities.Avatar.ElementSphere.Fire.BurnDuration", 3000); - config.addDefault("Abilities.Avatar.ElementSphere.Fire.Speed", 3); - config.addDefault("Abilities.Avatar.ElementSphere.Fire.Controllable", false); - config.addDefault("Abilities.Avatar.ElementSphere.Water.Cooldown", 500); - config.addDefault("Abilities.Avatar.ElementSphere.Water.Range", 40); - config.addDefault("Abilities.Avatar.ElementSphere.Water.Uses", 20); - config.addDefault("Abilities.Avatar.ElementSphere.Water.Damage", 3.0); - config.addDefault("Abilities.Avatar.ElementSphere.Water.Speed", 3); - config.addDefault("Abilities.Avatar.ElementSphere.Stream.Cooldown", 500); - config.addDefault("Abilities.Avatar.ElementSphere.Stream.Range", 40); - config.addDefault("Abilities.Avatar.ElementSphere.Stream.Knockback", 2.0); - config.addDefault("Abilities.Avatar.ElementSphere.Stream.Damage", 12.0); - config.addDefault("Abilities.Avatar.ElementSphere.Stream.RequiredUses", 10); - config.addDefault("Abilities.Avatar.ElementSphere.Stream.EndAbility", true); - config.addDefault("Abilities.Avatar.ElementSphere.Stream.ImpactCraterSize", 3); - config.addDefault("Abilities.Avatar.ElementSphere.Stream.ImpactRevert", 30000); - - config.addDefault("Abilities.Avatar.SpiritBeam.Enabled", true); - config.addDefault("Abilities.Avatar.SpiritBeam.Description", "An energybending ability usable by the Avatar. " - + "To use, one must enter the AvatarState and hold down Sneak (Default: Shift). " - + "This ability lasts only for a few seconds before requiring " - + "another activation."); - config.addDefault("Abilities.Avatar.SpiritBeam.Cooldown", 15000); - config.addDefault("Abilities.Avatar.SpiritBeam.Duration", 1000); - config.addDefault("Abilities.Avatar.SpiritBeam.Range", 40); - config.addDefault("Abilities.Avatar.SpiritBeam.Damage", 10.0); - config.addDefault("Abilities.Avatar.SpiritBeam.AvatarStateOnly", true); - config.addDefault("Abilities.Avatar.SpiritBeam.BlockDamage.Enabled", true); - config.addDefault("Abilities.Avatar.SpiritBeam.BlockDamage.Radius", 3); - config.addDefault("Abilities.Avatar.SpiritBeam.BlockDamage.Regen", 20000); - - config.addDefault("Abilities.Air.AirBlade.Enabled", true); - config.addDefault("Abilities.Air.AirBlade.Description", "With this ability bound, Left-Click to shoot " - + "a strong blade of air at your targets doing some damage!"); - config.addDefault("Abilities.Air.AirBlade.Cooldown", 3000); - config.addDefault("Abilities.Air.AirBlade.Range", 30.0); - config.addDefault("Abilities.Air.AirBlade.Damage", 4.0); - config.addDefault("Abilities.Air.AirBlade.EntityCollisionRadius", 1.0); - config.addDefault("Abilities.Air.AirBlade.AbilityCollisionRadius", 1.0); - config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlast.Enabled",true); - config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlast.RemoveFirst",true); - config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlast.RemoveSecond",true); - config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlastCharged.Enabled",true); - config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlastCharged.RemoveFirst",true); - config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlastCharged.RemoveSecond",false); - - config.addDefault("Abilities.Air.AirBreath.Enabled", true); - config.addDefault("Abilities.Air.AirBreath.Description", "To use, hold Sneak (Default: Shift) to release " - + "a strong breath of wind knocking your opponents " - + "back. This ability also has a longer range and " - + "stronger knockback while in AvatarState!"); - config.addDefault("Abilities.Air.AirBreath.Cooldown", 3000); - config.addDefault("Abilities.Air.AirBreath.Duration", 3000); - config.addDefault("Abilities.Air.AirBreath.Particles", 3); - config.addDefault("Abilities.Air.AirBreath.AffectBlocks.Lava", true); - config.addDefault("Abilities.Air.AirBreath.AffectBlocks.Fire", true); - config.addDefault("Abilities.Air.AirBreath.ExtinguishEntities", true); - config.addDefault("Abilities.Air.AirBreath.Damage.Enabled", false); - config.addDefault("Abilities.Air.AirBreath.Damage.Player", 1.0); - config.addDefault("Abilities.Air.AirBreath.Damage.Mob", 2.0); - config.addDefault("Abilities.Air.AirBreath.Knockback", 0.8); - config.addDefault("Abilities.Air.AirBreath.Range", 10); - config.addDefault("Abilities.Air.AirBreath.LaunchPower", 1.0); - config.addDefault("Abilities.Air.AirBreath.RegenTargetOxygen", true); - config.addDefault("Abilities.Air.AirBreath.Avatar.Enabled", true); - config.addDefault("Abilities.Air.AirBreath.Avatar.Range", 20); - config.addDefault("Abilities.Air.AirBreath.Avatar.Knockback", 3.5); - - config.addDefault("Abilities.Air.AirGlide.Enabled", true); - config.addDefault("Abilities.Air.AirGlide.Description", "While falling, tap Sneak for a " - + "slow and steady descent, tap Sneak again to stop gliding."); - config.addDefault("Abilities.Air.AirGlide.Speed", 0.5); - config.addDefault("Abilities.Air.AirGlide.FallSpeed", 0.1); - config.addDefault("Abilities.Air.AirGlide.Particles", 4); - config.addDefault("Abilities.Air.AirGlide.AllowAirSpout", false); - config.addDefault("Abilities.Air.AirGlide.Cooldown", 0); - config.addDefault("Abilities.Air.AirGlide.Duration", 0); - config.addDefault("Abilities.Air.AirGlide.RequireGround", false); - - config.addDefault("Abilities.Air.AirPunch.Enabled", true); - config.addDefault("Abilities.Air.AirPunch.Description", "Left-Click in rapid succession to punch high desnity packets of air " - + "at enemies to do slight damage to them. A few punches can be thrown before the ability has a cooldown."); - config.addDefault("Abilities.Air.AirPunch.Cooldown", 5000); - config.addDefault("Abilities.Air.AirPunch.Threshold", 500); - config.addDefault("Abilities.Air.AirPunch.Shots", 4); - config.addDefault("Abilities.Air.AirPunch.Range", 30); - config.addDefault("Abilities.Air.AirPunch.Damage", 1.0); - config.addDefault("Abilities.Air.AirPunch.EntityCollisionRadius", 1.0); - config.addDefault("Abilities.Air.AirPunch.AbilityCollisionRadius", 1.0); - config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlast.Enabled", true); - config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlast.RemoveFirst", true); - config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlast.RemoveSecond", false); - config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlastCharged.Enabled",true); - config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlastCharged.RemoveFirst",true); - config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlastCharged.RemoveSecond",false); - config.addDefault("Abilities.Air.AirPunch.Collisions.AirBlade.Enabled", true); - config.addDefault("Abilities.Air.AirPunch.Collisions.AirBlade.RemoveFirst", true); - config.addDefault("Abilities.Air.AirPunch.Collisions.AirBlade.RemoveSecond", false); - - config.addDefault("Abilities.Air.Meditate.Enabled", true); - config.addDefault("Abilities.Air.Meditate.Description", "Hold Sneak (Default: Shift) to start meditating. " - + "After you have focused your energy, you will obtain several buffs."); - config.addDefault("Abilities.Air.Meditate.UnfocusMessage", "You have become unfocused from taking damage!"); - config.addDefault("Abilities.Air.Meditate.LossFocusMessage", true); - config.addDefault("Abilities.Air.Meditate.ChargeTime", 5000); - config.addDefault("Abilities.Air.Meditate.Cooldown", 60000); - config.addDefault("Abilities.Air.Meditate.BoostDuration", 20000); - config.addDefault("Abilities.Air.Meditate.ParticleDensity", 5); - config.addDefault("Abilities.Air.Meditate.AbsorptionBoost", 2); - config.addDefault("Abilities.Air.Meditate.SpeedBoost", 3); - config.addDefault("Abilities.Air.Meditate.JumpBoost", 3); - - config.addDefault("Abilities.Air.SonicBlast.Enabled", true); - config.addDefault("Abilities.Air.SonicBlast.Description", "SonicBlast is a soundbending ability, known by very few airbenders. " - + "It allows the airbender to stun and deafen an opponent by creating a sonic blast, " - + "this is achieved by creating two regions of high and low pressure and bringing them together. " - + "To use, hold Sneak (Default: Shift) in the direction of the target. Once particles start appearing " - + "around you, let go of Sneak to shoot a SonicBlast at your target! The technique is very powerful, " - + "even if it doesn't seem it, and comes with a short cooldown."); - config.addDefault("Abilities.Air.SonicBlast.ChargeTime", 2000); - config.addDefault("Abilities.Air.SonicBlast.Damage", 4.0); - config.addDefault("Abilities.Air.SonicBlast.Effects.BlindnessDuration", 5000); - config.addDefault("Abilities.Air.SonicBlast.Effects.NauseaDuration", 5000); - config.addDefault("Abilities.Air.SonicBlast.Cooldown", 6000); - config.addDefault("Abilities.Air.SonicBlast.EntityCollisionRadius", 1.3); - config.addDefault("Abilities.Air.SonicBlast.AbilityCollisionRadius", 1.3); - config.addDefault("Abilities.Air.SonicBlast.Range", 20); - config.addDefault("Abilities.Air.SonicBlast.ChargeSwapping", true); - - config.addDefault("Abilities.Air.AirCombo.AirSlam.Enabled", true); - config.addDefault("Abilities.Air.AirCombo.AirSlam.Description", "Kick your enemy up into the air then blast them away!"); - config.addDefault("Abilities.Air.AirCombo.AirSlam.Cooldown", 8000); - config.addDefault("Abilities.Air.AirCombo.AirSlam.Power", 5.0); - config.addDefault("Abilities.Air.AirCombo.AirSlam.Range", 8); - config.addDefault("Abilities.Air.AirCombo.AirSlam.Combination", Arrays.asList("AirSwipe:SHIFT_DOWN", "AirBlast:SHIFT_UP", "AirBlast:SHIFT_DOWN")); - config.addDefault("Abilities.Air.AirCombo.AirSlam.Instructions", "AirSwipe (Hold sneak) > AirBlast (Release sneak) > AirBlast (Hold sneak)"); - - config.addDefault("Abilities.Air.AirCombo.SwiftStream.Enabled", true); - config.addDefault("Abilities.Air.AirCombo.SwiftStream.Description", "Create a stream of air as you fly which causes nearby " - + "entities to be thrown in your direction."); - config.addDefault("Abilities.Air.AirCombo.SwiftStream.DragFactor", 1.5); - config.addDefault("Abilities.Air.AirCombo.SwiftStream.Duration", 2000); - config.addDefault("Abilities.Air.AirCombo.SwiftStream.Cooldown", 6000); - config.addDefault("Abilities.Air.AirCombo.SwiftStream.Combination", Arrays.asList("Flight:SHIFT_DOWN", "Flight:SHIFT_UP", "Flight:SHIFT_DOWN", "Flight:SHIFT_UP")); - config.addDefault("Abilities.Air.AirCombo.SwiftStream.Instructions", "Flight (Double tap sneak)"); - - config.addDefault("Abilities.Earth.EarthArmor.Enabled", true); - config.addDefault("Abilities.Earth.EarthArmor.Description", "If the block is metal, then you will get metal armor!"); - config.addDefault("Abilities.Earth.EarthArmor.Resistance.Strength", 2); - config.addDefault("Abilities.Earth.EarthArmor.Resistance.Duration", 4000); - config.addDefault("Abilities.Earth.EarthArmor.UseIronArmor", false); - - config.addDefault("Abilities.Earth.EarthKick.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Description", "This move enables an earthbender to create a " - + "large earthen cover, ideal for defense. " - + "To use, Sneak (Default: Shift) at an earth " - + "source and it will raise and launch towards " - + "your foe!"); - config.addDefault("Abilities.Earth.EarthKick.Cooldown", 2000); - config.addDefault("Abilities.Earth.EarthKick.EarthBlocks", 10); - config.addDefault("Abilities.Earth.EarthKick.Damage", 2.0); - config.addDefault("Abilities.Earth.EarthKick.EntityCollisionRadius", 1.5); - config.addDefault("Abilities.Earth.EarthKick.AbilityCollisionRadius", 1.5); - config.addDefault("Abilities.Earth.EarthKick.MultipleHits", true); - config.addDefault("Abilities.Earth.EarthKick.SourceRange", 2.0); - config.addDefault("Abilities.Earth.EarthKick.Spread", 20); - config.addDefault("Abilities.Earth.EarthKick.Velocity", 0.7); - config.addDefault("Abilities.Earth.EarthKick.Collisions.FireBlast.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.FireBlast.RemoveFirst", false); - config.addDefault("Abilities.Earth.EarthKick.Collisions.FireBlast.RemoveSecond", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.EarthBlast.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.EarthBlast.RemoveFirst", false); - config.addDefault("Abilities.Earth.EarthKick.Collisions.EarthBlast.RemoveSecond", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterManipulation.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterManipulation.RemoveFirst", false); - config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterManipulation.RemoveSecond", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSwipe.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSwipe.RemoveFirst", false); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSwipe.RemoveSecond", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.Combustion.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.Combustion.RemoveFirst", false); - config.addDefault("Abilities.Earth.EarthKick.Collisions.Combustion.RemoveSecond", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterSpout.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterSpout.RemoveFirst", false); - config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterSpout.RemoveSecond", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSpout.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSpout.RemoveFirst", false); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSpout.RemoveSecond", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirWheel.Enabled", true); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirWheel.RemoveFirst", false); - config.addDefault("Abilities.Earth.EarthKick.Collisions.AirWheel.RemoveSecond", true); - - - config.addDefault("Abilities.Earth.EarthLine.Enabled", true); - config.addDefault("Abilities.Earth.EarthLine.Description", "To use, place your cursor over an earth-bendable block on the ground, " - + "then Sneak (Default: Shift) to select the block. After selecting the block you may release Sneak. " - + "If you then Left-Click at an object or player, a small piece of earth will come up " - + "from the ground and move towards your target to deal damage and knock them back. " - + "Additionally, hold Sneak to control the flow of the line!"); - config.addDefault("Abilities.Earth.EarthLine.Cooldown", 0); - config.addDefault("Abilities.Earth.EarthLine.PrepareCooldown", 3000); - config.addDefault("Abilities.Earth.EarthLine.Range", 30); - config.addDefault("Abilities.Earth.EarthLine.PrepareRange", 3); - config.addDefault("Abilities.Earth.EarthLine.SourceKeepRange", 7); - config.addDefault("Abilities.Earth.EarthLine.AffectingRadius", 2); - config.addDefault("Abilities.Earth.EarthLine.AllowChangeDirection", true); - config.addDefault("Abilities.Earth.EarthLine.MaxDuration", 2500); - config.addDefault("Abilities.Earth.EarthLine.Damage", 3.0); - config.addDefault("Abilities.Earth.EarthLine.RemovalPolicy.SwappedSlots.Enabled", false); - - config.addDefault("Abilities.Earth.EarthPillar.Enabled", true); - config.addDefault("Abilities.Earth.EarthPillar.Description", "With this ability bound, tap Sneak (Default: Shift) on any Earthbendable " - + "surface to create pillar of earth in the direction of the block face!"); - config.addDefault("Abilities.Earth.EarthPillar.Height", 6); - config.addDefault("Abilities.Earth.EarthPillar.Range", 10); - - config.addDefault("Abilities.Earth.EarthShard.Enabled", true); - config.addDefault("Abilities.Earth.EarthShard.Description", "EarthShard is a variation of EarthBlast " - + "which the earthbender may use to hit a target. This " - + "ability deals a fair amount of damage and is easy to " - + "rapid-fire. To use, simply shift at an earthbendable block, " - + "and it will ascend to your eye height. Then, click towards your " - + "target and the block will launch itself towards it."); - config.addDefault("Abilities.Earth.EarthShard.Cooldown", 1000); - config.addDefault("Abilities.Earth.EarthShard.Damage.Normal", 1.0); - config.addDefault("Abilities.Earth.EarthShard.Damage.Metal", 1.5); - config.addDefault("Abilities.Earth.EarthShard.PrepareRange", 5); - config.addDefault("Abilities.Earth.EarthShard.AbilityRange", 30); - config.addDefault("Abilities.Earth.EarthShard.MaxShards", 3); - config.addDefault("Abilities.Earth.EarthShard.AbilityCollisionRadius", 2.0); - config.addDefault("Abilities.Earth.EarthShard.EntityCollisionRadius", 1.4); - - config.addDefault("Abilities.Earth.EarthSurf.Enabled", true); - config.addDefault("Abilities.Earth.EarthSurf.Description", "This ability allows an earth bender to " - + "ride up on a wave of earth, allowing them to travel a little faster than " - + "normal. To use, simply be in the air just above " - + "the ground, and Left Click! Additionally, if an entity just so happens to get caught in " - + "the wave, they will be moved with the wave."); - config.addDefault("Abilities.Earth.EarthSurf.Cooldown.Cooldown", 3000); - config.addDefault("Abilities.Earth.EarthSurf.Cooldown.MinimumCooldown", 2000); - config.addDefault("Abilities.Earth.EarthSurf.Cooldown.Scaled", true); - config.addDefault("Abilities.Earth.EarthSurf.Cooldown.Enabled", false); - config.addDefault("Abilities.Earth.EarthSurf.Duration.Duration", 7000); - config.addDefault("Abilities.Earth.EarthSurf.Duration.Enabled", false); - config.addDefault("Abilities.Earth.EarthSurf.RelaxedCollisions", true); - config.addDefault("Abilities.Earth.EarthSurf.RemoveOnAnyDamage", false); - config.addDefault("Abilities.Earth.EarthSurf.Speed", 0.55); - config.addDefault("Abilities.Earth.EarthSurf.HeightTolerance", 3); - config.addDefault("Abilities.Earth.EarthSurf.SpringStiffness", 0.35); - - config.addDefault("Abilities.Earth.Fissure.Enabled", true); - config.addDefault("Abilities.Earth.Fissure.Description", "Fissure is an advanced Lavabending " - + "ability enabling a lavabender to tear up the ground, " - + "swallowing up any enemies. To use, simply swing at an enemy " - + "and a line of lava will crack open. " - + "Then, tap Sneak (Default: Shift) to expand the crevice. " - + "The crevice has a maximum width and depth. Once the crevice has reached it's maximum " - + "width, Sneak while looking at the crevice to close it!"); - config.addDefault("Abilities.Earth.Fissure.Cooldown", 20000); - config.addDefault("Abilities.Earth.Fissure.Duration", 15000); - config.addDefault("Abilities.Earth.Fissure.MaxWidth", 3); - config.addDefault("Abilities.Earth.Fissure.SlapRange", 12); - config.addDefault("Abilities.Earth.Fissure.SlapDelay", 50); - - config.addDefault("Abilities.Earth.LavaDisc.Enabled", true); - config.addDefault("Abilities.Earth.LavaDisc.Description", "Hold Sneak (Default: Shift) on a lava source " - + "block to generate a disc of lava at your finger tips. Releasing " - + "Sneak will shoot the disc off in the direction " - + "you are looking! If you tap or hold Sneak again, " - + "the disc will attempt to return to you!"); - String[] meltable = { - Material.COBBLESTONE.name(), Material.OAK_LOG.name(), Material.SPRUCE_LOG.name(), - Material.JUNGLE_LOG.name(), Material.DARK_OAK_LOG.name(), Material.BIRCH_LOG.name(), - Material.ACACIA_LOG.name() - }; - config.addDefault("Abilities.Earth.LavaDisc.Cooldown", 7000); - config.addDefault("Abilities.Earth.LavaDisc.Duration", 1000); - config.addDefault("Abilities.Earth.LavaDisc.Damage", 4.0); - config.addDefault("Abilities.Earth.LavaDisc.Particles", 3); - config.addDefault("Abilities.Earth.LavaDisc.ContinueAfterEntityHit", false); - config.addDefault("Abilities.Earth.LavaDisc.RecallLimit", 3); - config.addDefault("Abilities.Earth.LavaDisc.Destroy.RegenTime", 5000); - config.addDefault("Abilities.Earth.LavaDisc.Destroy.BlockDamage", true); - config.addDefault("Abilities.Earth.LavaDisc.Destroy.AdditionalMeltableBlocks", meltable); - config.addDefault("Abilities.Earth.LavaDisc.Destroy.LavaTrail", true); - config.addDefault("Abilities.Earth.LavaDisc.Destroy.TrailFlow", false); - config.addDefault("Abilities.Earth.LavaDisc.Source.RegenTime", 10000); - config.addDefault("Abilities.Earth.LavaDisc.Source.LavaOnly", false); - config.addDefault("Abilities.Earth.LavaDisc.Source.Range", 4.0); - config.addDefault("Abilities.Earth.LavaDisc.RemovalPolicy.SwappedSlots.Enabled", true); - - config.addDefault("Abilities.Earth.LavaFlux.Enabled", true); - config.addDefault("Abilities.Earth.LavaFlux.Description", "This offensive ability enables a Lavabender to create a wave of lava, " - + "swiftly progressing forward and hurting/burning anything in its way. To use, " - + "simply swing your arm towards a target and the ability will activate."); - config.addDefault("Abilities.Earth.LavaFlux.Range", 12); - config.addDefault("Abilities.Earth.LavaFlux.Cooldown", 8000); - config.addDefault("Abilities.Earth.LavaFlux.Duration", 4000); - config.addDefault("Abilities.Earth.LavaFlux.Cleanup", 1000); - config.addDefault("Abilities.Earth.LavaFlux.Damage", 1.0); - config.addDefault("Abilities.Earth.LavaFlux.Speed", 1); - config.addDefault("Abilities.Earth.LavaFlux.Wave", true); - config.addDefault("Abilities.Earth.LavaFlux.KnockUp", 1.0); - config.addDefault("Abilities.Earth.LavaFlux.KnockBack", 1.0); - - config.addDefault("Abilities.Earth.LavaThrow.Enabled", true); - config.addDefault("Abilities.Earth.LavaThrow.Description", "Throwing lava is a fundamental technique for the rare subskill. " - + "Use Sneak(Deafult: Shift) while looking at a pool of lava infront of you, then " - + "Left-Click to splash the lava at your target. " - + "It can be used in rapid succession to create multiple streams of lava!"); - config.addDefault("Abilities.Earth.LavaThrow.Cooldown", 7000); - config.addDefault("Abilities.Earth.LavaThrow.MaxShots", 6); - config.addDefault("Abilities.Earth.LavaThrow.Range", 20); - config.addDefault("Abilities.Earth.LavaThrow.Damage", 1.0); - config.addDefault("Abilities.Earth.LavaThrow.SourceGrabRange", 4); - config.addDefault("Abilities.Earth.LavaThrow.SourceRegenDelay", 10000); - config.addDefault("Abilities.Earth.LavaThrow.FireTicks", 80); - - config.addDefault("Abilities.Earth.MagnetShield.Enabled", true); - config.addDefault("Abilities.Earth.MagnetShield.Description", "Repel any metal projectiles using a strong magnetic shield. " - + "To activate, simply hold sneak with this ability bound."); - config.addDefault("Abilities.Earth.MagnetShield.Materials", Arrays.asList( - "IRON_INGOT", - "IRON_HELMET", - "IRON_CHESTPLATE", - "IRON_LEGGINGS", - "IRON_BOOTS", - "IRON_BLOCK", - "IRON_AXE", - "IRON_PICKAXE", - "IRON_SWORD", - "IRON_HOE", - "IRON_SHOVEL", - "IRON_DOOR", - "IRON_NUGGET", - "IRON_BARS", - "IRON_HORSE_ARMOR", - "IRON_TRAPDOOR", - "HEAVY_WEIGHTED_PRESSURE_PLATE", - "GOLD_INGOT", - "GOLDEN_HELMET", - "GOLDEN_CHESTPLATE", - "GOLDEN_LEGGINGS", - "GOLDEN_BOOTS", - "GOLD_BLOCK", - "GOLD_NUGGET", - "GOLDEN_AXE", - "GOLDEN_PICKAXE", - "GOLDEN_SHOVEL", - "GOLDEN_SWORD", - "GOLDEN_HOE", - "GOLDEN_HORSE_ARMOR", - "LIGHT_WEIGHTED_PRESSURE_PLATE", - "CLOCK", - "COMPASS", - "RAW_GOLD_BLOCK", - "RAW_IRON_BLOCK", - "RAW_IRON", - "RAW_GOLD", - "ANVIL", - "CHIPPED_ANVIL", - "DAMAGED_ANVIL", - "IRON_ORE", - "GOLD_ORE", - "DEEPSLATE_IRON_ORE", - "DEEPSLATE_GOLD_ORE", - "SHIELD" - )); - config.addDefault("Abilities.Earth.MagnetShield.Duration", 6000); - config.addDefault("Abilities.Earth.MagnetShield.Cooldowns.Shift", 5000); - config.addDefault("Abilities.Earth.MagnetShield.Cooldowns.Click", 5000); - config.addDefault("Abilities.Earth.MagnetShield.Range", 5.0); - config.addDefault("Abilities.Earth.MagnetShield.RepelArrows", true); - config.addDefault("Abilities.Earth.MagnetShield.RepelLivingEntities", true); - config.addDefault("Abilities.Earth.MagnetShield.Velocity", 0.1); - - config.addDefault("Abilities.Earth.MetalFragments.Enabled", true); - config.addDefault("Abilities.Earth.MetalFragments.Description", "MetalFragments allows you to select a source and shoot " - + "multiple fragments of metal out of that source " - + "block towards your target, injuring them on impact. " - + "To use, tap Sneak (Default: Shift) at a metal " - + "source block and it will float up. Then, turn around " - + "and click at your target to fling metal fragments at them."); - config.addDefault("Abilities.Earth.MetalFragments.Cooldown", 5000); - config.addDefault("Abilities.Earth.MetalFragments.MaxSources", 3); - config.addDefault("Abilities.Earth.MetalFragments.SourceRange", 5); - config.addDefault("Abilities.Earth.MetalFragments.MaxFragments", 10); - config.addDefault("Abilities.Earth.MetalFragments.Damage", 4.0); - config.addDefault("Abilities.Earth.MetalFragments.Velocity", 2.0); - - config.addDefault("Abilities.Earth.MetalHook.Enabled", true); - config.addDefault("Abilities.Earth.MetalHook.Description", "This ability lets a Metalbender bend metal into " - + "grappling hooks, allowing them to easily manouver terrain. " - + "To use this ability, the user must either have Iron in their inventory " - + "or be wearing an Iron/Chainmail Chestplate. Left-Click in the direction " - + "you are looking to fire a grappling hook, several hooks can be active at once, " - + "allowing the bender to 'hang' in locations. To disengage the hooks, hold Shift (Default: Sneak) or Sprint."); - config.addDefault("Abilities.Earth.MetalHook.Cooldown", 3000); - config.addDefault("Abilities.Earth.MetalHook.Range", 30); - config.addDefault("Abilities.Earth.MetalHook.MaxHooks", 3); - config.addDefault("Abilities.Earth.MetalHook.TotalHooks", 0); - config.addDefault("Abilities.Earth.MetalHook.RequireItems", true); - config.addDefault("Abilities.Earth.MetalHook.BarrierHooking", true); - - config.addDefault("Abilities.Earth.MetalShred.Enabled", true); - config.addDefault("Abilities.Earth.MetalShred.Description", "MetalShred allows you to tear a metal surface allowing you to sneak in to the other side." - + "To use, you must find a flat metal surface. Then, Sneak(Default: Shift) " - + "at a piece of metal on that surface, and two pieces of metal " - + "will be pulled toward you. Finally, run alongside the surface to coil " - + "the metal around those two pieces. The way will be open, and the blocks " - + "will not reset until you either select a new source or you switch " - + "abilities. If you click after having torn a hole in a vertical surface, " - + "you can Left-Click in any direction and the metal will unfold in that " - + "direction. If you are fast and precise enough, the metal can bend in " - + "any shape. The length of this sheet of metal depends on how much was " - + "coiled in the first place."); - config.addDefault("Abilities.Earth.MetalShred.SourceRange", 5); + static JedCore plugin; + public static Config board; + + public JedCoreConfig(JedCore plugin) { + JedCoreConfig.plugin = plugin; + board = new Config(new File("board.yml")); + loadConfigBoard(); + loadConfigCore(); + addDeathMessages(); + setupElementSphereNames(); + } + + private void loadConfigBoard() { + FileConfiguration config; + config = board.getConfig(); + config.addDefault("Settings.Enabled", false); + config.options().copyDefaults(true); + board.saveConfig(); + } + + private void loadConfigCore() { + FileConfiguration config; + config = JedCore.plugin.getConfig(); + + config.addDefault("Settings.Updater.Check", true); + config.addDefault("Settings.Updater.Notify", true); + config.addDefault("Properties.MobCollisions.Enabled", true); + config.addDefault("Properties.AbilityCollisions.Enabled", true); + config.addDefault("Properties.PerWorldConfig", true); + config.addDefault("Properties.FireTickMethod", "larger"); + config.addDefault("Properties.LogDebug", false); + + config.addDefault("Properties.ChiRestrictor.Enabled", false); + config.addDefault("Properties.ChiRestrictor.ResetCooldown", true); + config.addDefault("Properties.ChiRestrictor.MeleeDistance", 7); + config.addDefault("Properties.ChiRestrictor.Whitelist", new ArrayList()); + + config.addDefault("Properties.Fire.DynamicLight.Enabled", true); + config.addDefault("Properties.Fire.DynamicLight.Brightness", 13); + config.addDefault("Properties.Fire.DynamicLight.KeepAlive", 600); + + config.addDefault("Abilities.Avatar.ElementSphere.Enabled", true); + config.addDefault("Abilities.Avatar.ElementSphere.Description", "ElementSphere is a very all round ability, being " + + "able to shoot attacks of each element, each with a " + + "different effect. To use, simply Left-Click. Once active, " + + "Sneak (Default: Shift) to fly around. Sneak and double " + + "Left-Click to disable the ability! " + + "To use each element, simply select hotbar slots 1-4 and Left-Click. " + + "Each element has limited uses! Once an element is used up, " + + "the element's ring will disappear!"); + config.addDefault("Abilities.Avatar.ElementSphere.Cooldown", 180000); + config.addDefault("Abilities.Avatar.ElementSphere.Duration", 60000); + config.addDefault("Abilities.Avatar.ElementSphere.MaxControlledHeight", 40); + config.addDefault("Abilities.Avatar.ElementSphere.FlySpeed", 1.5); + config.addDefault("Abilities.Avatar.ElementSphere.Air.Cooldown", 500); + config.addDefault("Abilities.Avatar.ElementSphere.Air.Range", 40); + config.addDefault("Abilities.Avatar.ElementSphere.Air.Uses", 20); + config.addDefault("Abilities.Avatar.ElementSphere.Air.Damage", 3.0); + config.addDefault("Abilities.Avatar.ElementSphere.Air.Knockback", 2); + config.addDefault("Abilities.Avatar.ElementSphere.Air.Speed", 3); + config.addDefault("Abilities.Avatar.ElementSphere.Earth.Cooldown", 500); + config.addDefault("Abilities.Avatar.ElementSphere.Earth.Uses", 20); + config.addDefault("Abilities.Avatar.ElementSphere.Earth.Damage", 3.0); + config.addDefault("Abilities.Avatar.ElementSphere.Earth.ImpactCraterSize", 3); + config.addDefault("Abilities.Avatar.ElementSphere.Earth.ImpactRevert", 15000); + config.addDefault("Abilities.Avatar.ElementSphere.Fire.Cooldown", 500); + config.addDefault("Abilities.Avatar.ElementSphere.Fire.Range", 40); + config.addDefault("Abilities.Avatar.ElementSphere.Fire.Uses", 20); + config.addDefault("Abilities.Avatar.ElementSphere.Fire.Damage", 3.0); + config.addDefault("Abilities.Avatar.ElementSphere.Fire.BurnDuration", 3000); + config.addDefault("Abilities.Avatar.ElementSphere.Fire.Speed", 3); + config.addDefault("Abilities.Avatar.ElementSphere.Fire.Controllable", false); + config.addDefault("Abilities.Avatar.ElementSphere.Water.Cooldown", 500); + config.addDefault("Abilities.Avatar.ElementSphere.Water.Range", 40); + config.addDefault("Abilities.Avatar.ElementSphere.Water.Uses", 20); + config.addDefault("Abilities.Avatar.ElementSphere.Water.Damage", 3.0); + config.addDefault("Abilities.Avatar.ElementSphere.Water.Speed", 3); + config.addDefault("Abilities.Avatar.ElementSphere.Stream.Cooldown", 500); + config.addDefault("Abilities.Avatar.ElementSphere.Stream.Range", 40); + config.addDefault("Abilities.Avatar.ElementSphere.Stream.Knockback", 2.0); + config.addDefault("Abilities.Avatar.ElementSphere.Stream.Damage", 12.0); + config.addDefault("Abilities.Avatar.ElementSphere.Stream.RequiredUses", 10); + config.addDefault("Abilities.Avatar.ElementSphere.Stream.EndAbility", true); + config.addDefault("Abilities.Avatar.ElementSphere.Stream.ImpactCraterSize", 3); + config.addDefault("Abilities.Avatar.ElementSphere.Stream.ImpactRevert", 30000); + + config.addDefault("Abilities.Avatar.SpiritBeam.Enabled", true); + config.addDefault("Abilities.Avatar.SpiritBeam.Description", "An energybending ability usable by the Avatar. " + + "To use, one must enter the AvatarState and hold down Sneak (Default: Shift). " + + "This ability lasts only for a few seconds before requiring " + + "another activation."); + config.addDefault("Abilities.Avatar.SpiritBeam.Cooldown", 15000); + config.addDefault("Abilities.Avatar.SpiritBeam.Duration", 1000); + config.addDefault("Abilities.Avatar.SpiritBeam.Range", 40); + config.addDefault("Abilities.Avatar.SpiritBeam.Damage", 10.0); + config.addDefault("Abilities.Avatar.SpiritBeam.AvatarStateOnly", true); + config.addDefault("Abilities.Avatar.SpiritBeam.BlockDamage.Enabled", true); + config.addDefault("Abilities.Avatar.SpiritBeam.BlockDamage.Radius", 3); + config.addDefault("Abilities.Avatar.SpiritBeam.BlockDamage.Regen", 20000); + + config.addDefault("Abilities.Air.AirBlade.Enabled", true); + config.addDefault("Abilities.Air.AirBlade.Description", "With this ability bound, Left-Click to shoot " + + "a strong blade of air at your targets to deal some damage!"); + config.addDefault("Abilities.Air.AirBlade.Cooldown", 3000); + config.addDefault("Abilities.Air.AirBlade.Range", 30.0); + config.addDefault("Abilities.Air.AirBlade.Damage", 4.0); + config.addDefault("Abilities.Air.AirBlade.Speed", 1.0); + config.addDefault("Abilities.Air.AirBlade.Knockback", 0.0); + config.addDefault("Abilities.Air.AirBlade.EntityCollisionRadius", 1.0); + config.addDefault("Abilities.Air.AirBlade.AbilityCollisionRadius", 1.0); + config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlast.Enabled", true); + config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlast.RemoveFirst", true); + config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlast.RemoveSecond", true); + config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlastCharged.Enabled", true); + config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlastCharged.RemoveFirst", true); + config.addDefault("Abilities.Air.AirBlade.Collisions.FireBlastCharged.RemoveSecond", false); + config.addDefault("Abilities.Air.AirBlade.BlockCutting.Enabled", true); + config.addDefault("Abilities.Air.AirBlade.BlockCutting.Revert", true); + config.addDefault("Abilities.Air.AirBlade.BlockCutting.RevertTime", 5000); + config.addDefault("Abilities.Air.AirBlade.BlockCutting.Materials", Arrays.asList( + "#small_flowers", + "#flowers", + "#crops", + "#saplings", + "BIG_DRIPLEAF_STEM", + "BIG_DRIPLEAF", + "CAVE_VINES", + "CAVE_VINES_PLANT", + "VINE", + "FERN", + "LARGE_FERN", + "SHORT_GRASS", + "TALL_GRASS", + "DEAD_BUSH", + "SEA_PICKLE", + "CACTUS_FLOWER", + "BERRY_BUSH", + "RED_MUSHROOM", + "BROWN_MUSHROOM" + )); + + config.addDefault("Abilities.Air.AirBreath.Enabled", true); + config.addDefault("Abilities.Air.AirBreath.Description", "To use, hold Sneak (Default: Shift) to release " + + "a strong breath of wind, knocking your opponents " + + "back. This ability also has a longer range and " + + "stronger knockback while in AvatarState!"); + config.addDefault("Abilities.Air.AirBreath.Cooldown", 3000); + config.addDefault("Abilities.Air.AirBreath.Duration", 3000); + config.addDefault("Abilities.Air.AirBreath.Particles", 3); + config.addDefault("Abilities.Air.AirBreath.AffectBlocks.Lava", true); + config.addDefault("Abilities.Air.AirBreath.AffectBlocks.Fire", true); + config.addDefault("Abilities.Air.AirBreath.ExtinguishEntities", true); + config.addDefault("Abilities.Air.AirBreath.Damage.Enabled", false); + config.addDefault("Abilities.Air.AirBreath.Damage.Player", 1.0); + config.addDefault("Abilities.Air.AirBreath.Damage.Mob", 2.0); + config.addDefault("Abilities.Air.AirBreath.Knockback", 0.8); + config.addDefault("Abilities.Air.AirBreath.Range", 10); + config.addDefault("Abilities.Air.AirBreath.LaunchPower", 1.0); + config.addDefault("Abilities.Air.AirBreath.RegenTargetOxygen", true); + config.addDefault("Abilities.Air.AirBreath.Avatar.Enabled", true); + config.addDefault("Abilities.Air.AirBreath.Avatar.Range", 20); + config.addDefault("Abilities.Air.AirBreath.Avatar.Knockback", 3.5); + + config.addDefault("Abilities.Air.AirGlide.Enabled", true); + config.addDefault("Abilities.Air.AirGlide.Description", "While falling, tap Sneak for a " + + "slow and steady descent. Tap Sneak again to stop gliding."); + config.addDefault("Abilities.Air.AirGlide.Speed", 0.5); + config.addDefault("Abilities.Air.AirGlide.FallSpeed", 0.1); + config.addDefault("Abilities.Air.AirGlide.Particles", 4); + config.addDefault("Abilities.Air.AirGlide.AllowAirSpout", false); + config.addDefault("Abilities.Air.AirGlide.Cooldown", 0); + config.addDefault("Abilities.Air.AirGlide.Duration", 0); + config.addDefault("Abilities.Air.AirGlide.RequireGround", false); + + config.addDefault("Abilities.Air.AirPunch.Enabled", true); + config.addDefault("Abilities.Air.AirPunch.Description", "Left-Click in rapid succession to punch high desnity packets of air " + + "at enemies to do slight damage. A few punches can be thrown before the ability goes on cooldown."); + config.addDefault("Abilities.Air.AirPunch.Cooldown", 5000); + config.addDefault("Abilities.Air.AirPunch.Threshold", 500); + config.addDefault("Abilities.Air.AirPunch.Shots", 4); + config.addDefault("Abilities.Air.AirPunch.Range", 30); + config.addDefault("Abilities.Air.AirPunch.Damage", 1.0); + config.addDefault("Abilities.Air.AirPunch.Speed", 1.0); + config.addDefault("Abilities.Air.AirPunch.EntityCollisionRadius", 1.0); + config.addDefault("Abilities.Air.AirPunch.AbilityCollisionRadius", 1.0); + config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlast.Enabled", true); + config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlast.RemoveFirst", true); + config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlast.RemoveSecond", false); + config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlastCharged.Enabled",true); + config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlastCharged.RemoveFirst",true); + config.addDefault("Abilities.Air.AirPunch.Collisions.FireBlastCharged.RemoveSecond",false); + config.addDefault("Abilities.Air.AirPunch.Collisions.AirBlade.Enabled", true); + config.addDefault("Abilities.Air.AirPunch.Collisions.AirBlade.RemoveFirst", true); + config.addDefault("Abilities.Air.AirPunch.Collisions.AirBlade.RemoveSecond", false); + + config.addDefault("Abilities.Air.Meditate.Enabled", true); + config.addDefault("Abilities.Air.Meditate.Description", "Hold Sneak (Default: Shift) to start meditating. " + + "After you have focused your energy, you will obtain several buffs."); + config.addDefault("Abilities.Air.Meditate.UnfocusMessage", "You have become unfocused due to taking damage!"); + config.addDefault("Abilities.Air.Meditate.LossFocusMessage", true); + config.addDefault("Abilities.Air.Meditate.ChargeTime", 5000); + config.addDefault("Abilities.Air.Meditate.Cooldown", 60000); + config.addDefault("Abilities.Air.Meditate.BoostDuration", 20000); + config.addDefault("Abilities.Air.Meditate.ParticleDensity", 5); + config.addDefault("Abilities.Air.Meditate.AbsorptionBoost", 2); + config.addDefault("Abilities.Air.Meditate.SpeedBoost", 3); + config.addDefault("Abilities.Air.Meditate.JumpBoost", 3); + + config.addDefault("Abilities.Air.SonicBlast.Enabled", true); + config.addDefault("Abilities.Air.SonicBlast.Description", "SonicBlast is a soundbending ability, known by very few airbenders. " + + "It allows the airbender to stun and deafen an opponent by creating a sonic blast. " + + "This is achieved by creating two regions of high and low pressure and bringing them together. " + + "To use, hold Sneak (Default: Shift) in the direction of the target. Once particles appear " + + "around you, let go of Sneak to shoot a SonicBlast at your target! The technique is very powerful, " + + "even if it doesn't seem it, and comes with a short cooldown."); + config.addDefault("Abilities.Air.SonicBlast.ChargeTime", 2000); + config.addDefault("Abilities.Air.SonicBlast.Damage", 4.0); + config.addDefault("Abilities.Air.SonicBlast.Effects.BlindnessDuration", 5000); + config.addDefault("Abilities.Air.SonicBlast.Effects.NauseaDuration", 5000); + config.addDefault("Abilities.Air.SonicBlast.Cooldown", 6000); + config.addDefault("Abilities.Air.SonicBlast.EntityCollisionRadius", 1.3); + config.addDefault("Abilities.Air.SonicBlast.AbilityCollisionRadius", 1.3); + config.addDefault("Abilities.Air.SonicBlast.Range", 20); + config.addDefault("Abilities.Air.SonicBlast.ChargeSwapping", true); + + config.addDefault("Abilities.Air.AirCombo.AirSlam.Enabled", true); + config.addDefault("Abilities.Air.AirCombo.AirSlam.Description", "Kick your enemy up into the air then blast them away!"); + config.addDefault("Abilities.Air.AirCombo.AirSlam.Cooldown", 8000); + config.addDefault("Abilities.Air.AirCombo.AirSlam.Power", 5.0); + config.addDefault("Abilities.Air.AirCombo.AirSlam.Range", 8); + config.addDefault("Abilities.Air.AirCombo.AirSlam.Combination", Arrays.asList("AirSwipe:SHIFT_DOWN", "AirBlast:SHIFT_UP", "AirBlast:SHIFT_DOWN")); + config.addDefault("Abilities.Air.AirCombo.AirSlam.Instructions", "AirSwipe (Hold sneak) > AirBlast (Release sneak) > AirBlast (Hold sneak)"); + + config.addDefault("Abilities.Air.AirCombo.SwiftStream.Enabled", true); + config.addDefault("Abilities.Air.AirCombo.SwiftStream.Description", "Create a stream of air as you fly which causes nearby " + + "entities to be thrown in your direction."); + config.addDefault("Abilities.Air.AirCombo.SwiftStream.DragFactor", 1.5); + config.addDefault("Abilities.Air.AirCombo.SwiftStream.Duration", 2000); + config.addDefault("Abilities.Air.AirCombo.SwiftStream.Cooldown", 6000); + config.addDefault("Abilities.Air.AirCombo.SwiftStream.Combination", Arrays.asList("Flight:SHIFT_DOWN", "Flight:SHIFT_UP", "Flight:SHIFT_DOWN", "Flight:SHIFT_UP")); + config.addDefault("Abilities.Air.AirCombo.SwiftStream.Instructions", "Flight (Double tap sneak)"); + + config.addDefault("Abilities.Earth.EarthArmor.Enabled", true); + config.addDefault("Abilities.Earth.EarthArmor.Description", "If the block is metal, then you will get metal armor!"); + config.addDefault("Abilities.Earth.EarthArmor.Resistance.Strength", 2); + config.addDefault("Abilities.Earth.EarthArmor.Resistance.Duration", 4000); + config.addDefault("Abilities.Earth.EarthArmor.UseIronArmor", false); + + config.addDefault("Abilities.Earth.EarthKick.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Description", "This move enables an earthbender to create a " + + "large earthen cover, ideal for defense. " + + "To use, Sneak (Default: Shift) at an earth " + + "source and it will raise and launch towards " + + "your foe!"); + config.addDefault("Abilities.Earth.EarthKick.Cooldown", 2000); + config.addDefault("Abilities.Earth.EarthKick.EarthBlocks", 10); + + double oldDamage = 0.0; + if (config.contains("Abilities.Earth.EarthKick.Damage")) { + oldDamage = config.getDouble("Abilities.Earth.EarthKick.Damage"); + config.set("Abilities.Earth.EarthKick.Damage", null); + } + + config.addDefault("Abilities.Earth.EarthKick.Damage.Normal", oldDamage > 0.0 ? oldDamage : 2.0); + config.addDefault("Abilities.Earth.EarthKick.Damage.Metal", 3.0); + config.addDefault("Abilities.Earth.EarthKick.EntityCollisionRadius", 1.5); + config.addDefault("Abilities.Earth.EarthKick.AbilityCollisionRadius", 1.5); + config.addDefault("Abilities.Earth.EarthKick.MultipleHits", true); + config.addDefault("Abilities.Earth.EarthKick.SourceRange", 2.0); + config.addDefault("Abilities.Earth.EarthKick.Spread", 20); + config.addDefault("Abilities.Earth.EarthKick.Velocity", 0.7); + config.addDefault("Abilities.Earth.EarthKick.AllowMetal", true); + config.addDefault("Abilities.Earth.EarthKick.ReplaceSource", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.FireBlast.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.FireBlast.RemoveFirst", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.FireBlast.RemoveSecond", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.EarthBlast.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.EarthBlast.RemoveFirst", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.EarthBlast.RemoveSecond", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterManipulation.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterManipulation.RemoveFirst", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterManipulation.RemoveSecond", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSwipe.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSwipe.RemoveFirst", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSwipe.RemoveSecond", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.Combustion.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.Combustion.RemoveFirst", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.Combustion.RemoveSecond", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterSpout.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterSpout.RemoveFirst", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.WaterSpout.RemoveSecond", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSpout.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSpout.RemoveFirst", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirSpout.RemoveSecond", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirWheel.Enabled", true); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirWheel.RemoveFirst", false); + config.addDefault("Abilities.Earth.EarthKick.Collisions.AirWheel.RemoveSecond", true); + + + config.addDefault("Abilities.Earth.EarthLine.Enabled", true); + config.addDefault("Abilities.Earth.EarthLine.Description", "To use, place your cursor over an earth-bendable block on the ground, " + + "then Sneak (Default: Shift) to select the block. After selecting the block you may release Sneak. " + + "If you then Left-Click at an object or player, a small piece of earth will come up " + + "from the ground and move towards your target to deal damage and knock them back. " + + "Additionally, hold Sneak to control the flow of the line!"); + config.addDefault("Abilities.Earth.EarthLine.Cooldown", 3000); + config.addDefault("Abilities.Earth.EarthLine.PrepareCooldown", 0); + config.addDefault("Abilities.Earth.EarthLine.Range", 30); + config.addDefault("Abilities.Earth.EarthLine.PrepareRange", 3); + config.addDefault("Abilities.Earth.EarthLine.SourceKeepRange", 7); + config.addDefault("Abilities.Earth.EarthLine.AffectingRadius", 2); + config.addDefault("Abilities.Earth.EarthLine.AllowChangeDirection", true); + config.addDefault("Abilities.Earth.EarthLine.MaxDuration", 2500); + config.addDefault("Abilities.Earth.EarthLine.Damage", 3.0); + config.addDefault("Abilities.Earth.EarthLine.RemovalPolicy.SwappedSlots.Enabled", false); + + config.addDefault("Abilities.Earth.EarthPillar.Enabled", true); + config.addDefault("Abilities.Earth.EarthPillar.Description", "With this ability bound, tap Sneak (Default: Shift) on any Earthbendable " + + "surface to create pillar of earth in the direction of the block face!"); + config.addDefault("Abilities.Earth.EarthPillar.Height", 6); + config.addDefault("Abilities.Earth.EarthPillar.Range", 10); + + config.addDefault("Abilities.Earth.EarthShard.Enabled", true); + config.addDefault("Abilities.Earth.EarthShard.Description", "EarthShard is a variation of EarthBlast " + + "which the earthbender may use to hit a target. This " + + "ability deals a fair amount of damage and is easy to " + + "rapid-fire. To use, simply shift at an earthbendable block, " + + "and it will ascend to your eye height. Then, click towards your " + + "target and the block will launch itself towards it."); + config.addDefault("Abilities.Earth.EarthShard.Cooldown", 1000); + config.addDefault("Abilities.Earth.EarthShard.Damage.Normal", 1.0); + config.addDefault("Abilities.Earth.EarthShard.Damage.Metal", 1.5); + config.addDefault("Abilities.Earth.EarthShard.PrepareRange", 5); + config.addDefault("Abilities.Earth.EarthShard.AbilityRange", 30); + config.addDefault("Abilities.Earth.EarthShard.MaxShards", 3); + config.addDefault("Abilities.Earth.EarthShard.KnockUp.Others.Allow", true); + config.addDefault("Abilities.Earth.EarthShard.KnockUp.Others.Velocity", 1.0); + config.addDefault("Abilities.Earth.EarthShard.KnockUp.Others.Range", 1.5); + config.addDefault("Abilities.Earth.EarthShard.KnockUp.Self.Allow", true); + config.addDefault("Abilities.Earth.EarthShard.KnockUp.Self.Velocity", 1.0); + config.addDefault("Abilities.Earth.EarthShard.KnockUp.Self.Range", 1.5); +// config.addDefault("Abilities.Earth.EarthShard.KnockUp.Allow", true); +// config.addDefault("Abilities.Earth.EarthShard.KnockUp.Velocity", 1.0); + config.addDefault("Abilities.Earth.EarthShard.AbilityCollisionRadius", 2.0); + config.addDefault("Abilities.Earth.EarthShard.EntityCollisionRadius", 1.4); + + config.addDefault("Abilities.Earth.EarthSurf.Enabled", true); + config.addDefault("Abilities.Earth.EarthSurf.Description", "This ability allows an earth bender to " + + "ride up on a wave of earth, allowing them to travel a little faster than " + + "normal. To use, simply be in the air just above " + + "the ground, and Left Click! Additionally, if an entity just so happens to get caught in " + + "the wave, they will be moved with the wave."); + config.addDefault("Abilities.Earth.EarthSurf.Cooldown.Cooldown", 3000); + config.addDefault("Abilities.Earth.EarthSurf.Cooldown.MinimumCooldown", 2000); + config.addDefault("Abilities.Earth.EarthSurf.Cooldown.Scaled", true); + config.addDefault("Abilities.Earth.EarthSurf.Cooldown.Enabled", false); + config.addDefault("Abilities.Earth.EarthSurf.Duration.Duration", 7000); + config.addDefault("Abilities.Earth.EarthSurf.Duration.Enabled", false); + config.addDefault("Abilities.Earth.EarthSurf.RelaxedCollisions", true); + config.addDefault("Abilities.Earth.EarthSurf.RemoveOnAnyDamage", false); + config.addDefault("Abilities.Earth.EarthSurf.Speed", 0.55); + config.addDefault("Abilities.Earth.EarthSurf.HeightTolerance", 3); + config.addDefault("Abilities.Earth.EarthSurf.SpringStiffness", 0.35); + + config.addDefault("Abilities.Earth.Fissure.Enabled", true); + config.addDefault("Abilities.Earth.Fissure.Description", "Fissure is an advanced Lavabending " + + "ability enabling a lavabender to tear up the ground, " + + "swallowing up any enemies. To use, simply swing at an enemy " + + "and a line of lava will crack open. " + + "Then, tap Sneak (Default: Shift) to expand the crevice. " + + "The crevice has a maximum width and depth. Once the crevice has reached it's maximum " + + "width, Sneak while looking at the crevice to close it!"); + config.addDefault("Abilities.Earth.Fissure.Cooldown", 20000); + config.addDefault("Abilities.Earth.Fissure.Duration", 15000); + config.addDefault("Abilities.Earth.Fissure.MaxWidth", 3); + config.addDefault("Abilities.Earth.Fissure.SlapRange", 12); + config.addDefault("Abilities.Earth.Fissure.SlapDelay", 50); + + config.addDefault("Abilities.Earth.LavaDisc.Enabled", true); + config.addDefault("Abilities.Earth.LavaDisc.Description", "Hold Sneak (Default: Shift) on a lava source " + + "block to generate a disc of lava at your finger tips. Releasing " + + "Sneak will shoot the disc off in the direction " + + "you are looking! If you tap or hold Sneak again, " + + "the disc will attempt to return to you!"); + String[] meltable = { + Material.COBBLESTONE.name(), Material.OAK_LOG.name(), Material.SPRUCE_LOG.name(), + Material.JUNGLE_LOG.name(), Material.DARK_OAK_LOG.name(), Material.BIRCH_LOG.name(), + Material.ACACIA_LOG.name() + }; + config.addDefault("Abilities.Earth.LavaDisc.Cooldown", 7000); + config.addDefault("Abilities.Earth.LavaDisc.Duration", 1000); + config.addDefault("Abilities.Earth.LavaDisc.Damage", 4.0); + config.addDefault("Abilities.Earth.LavaDisc.Particles", 3); + config.addDefault("Abilities.Earth.LavaDisc.ContinueAfterEntityHit", false); + config.addDefault("Abilities.Earth.LavaDisc.RecallLimit", 3); + config.addDefault("Abilities.Earth.LavaDisc.Destroy.RegenTime", 5000); + config.addDefault("Abilities.Earth.LavaDisc.Destroy.BlockDamage", true); + config.addDefault("Abilities.Earth.LavaDisc.Destroy.AdditionalMeltableBlocks", meltable); + config.addDefault("Abilities.Earth.LavaDisc.Destroy.LavaTrail", true); + config.addDefault("Abilities.Earth.LavaDisc.Destroy.TrailFlow", false); + config.addDefault("Abilities.Earth.LavaDisc.Source.RegenTime", 10000); + config.addDefault("Abilities.Earth.LavaDisc.Source.LavaOnly", false); + config.addDefault("Abilities.Earth.LavaDisc.Source.Range", 4.0); + config.addDefault("Abilities.Earth.LavaDisc.RemovalPolicy.SwappedSlots.Enabled", true); + + config.addDefault("Abilities.Earth.LavaFlux.Enabled", true); + config.addDefault("Abilities.Earth.LavaFlux.Description", "This offensive ability enables a Lavabender to create a wave of lava, " + + "swiftly progressing forward and hurting/burning anything in its way. To use, " + + "simply swing your arm towards a target and the ability will activate."); + config.addDefault("Abilities.Earth.LavaFlux.Range", 12); + config.addDefault("Abilities.Earth.LavaFlux.Cooldown", 8000); + config.addDefault("Abilities.Earth.LavaFlux.Duration", 4000); + config.addDefault("Abilities.Earth.LavaFlux.Cleanup", 1000); + config.addDefault("Abilities.Earth.LavaFlux.Damage", 1.0); + config.addDefault("Abilities.Earth.LavaFlux.Speed", 1); + config.addDefault("Abilities.Earth.LavaFlux.Wave", true); + config.addDefault("Abilities.Earth.LavaFlux.KnockUp", 1.0); + config.addDefault("Abilities.Earth.LavaFlux.KnockBack", 1.0); + + config.addDefault("Abilities.Earth.LavaThrow.Enabled", true); + config.addDefault("Abilities.Earth.LavaThrow.Description", "Throwing lava is a fundamental technique for the rare subskill. " + + "Use Sneak(Deafult: Shift) while looking at a pool of lava infront of you, then " + + "Left-Click to splash the lava at your target. " + + "It can be used in rapid succession to create multiple streams of lava!"); + config.addDefault("Abilities.Earth.LavaThrow.Cooldown", 7000); + config.addDefault("Abilities.Earth.LavaThrow.MaxShots", 6); + config.addDefault("Abilities.Earth.LavaThrow.Range", 20); + config.addDefault("Abilities.Earth.LavaThrow.Damage", 1.0); + config.addDefault("Abilities.Earth.LavaThrow.SourceGrabRange", 4); + config.addDefault("Abilities.Earth.LavaThrow.SourceRegenDelay", 10000); + config.addDefault("Abilities.Earth.LavaThrow.FireTicks", 80); + config.addDefault("Abilities.Earth.LavaThrow.CurveFactor", 0.5); + + config.addDefault("Abilities.Earth.MagnetShield.Enabled", true); + config.addDefault("Abilities.Earth.MagnetShield.Description", "Repel any metal projectiles using a strong magnetic shield. " + + "To activate, simply hold sneak with this ability bound."); + config.addDefault("Abilities.Earth.MagnetShield.Materials", Arrays.asList( + "IRON_INGOT", + "IRON_HELMET", + "IRON_CHESTPLATE", + "IRON_LEGGINGS", + "IRON_BOOTS", + "IRON_BLOCK", + "IRON_AXE", + "IRON_PICKAXE", + "IRON_SWORD", + "IRON_HOE", + "IRON_SHOVEL", + "IRON_DOOR", + "IRON_NUGGET", + "IRON_BARS", + "IRON_HORSE_ARMOR", + "IRON_TRAPDOOR", + "HEAVY_WEIGHTED_PRESSURE_PLATE", + "GOLD_INGOT", + "GOLDEN_HELMET", + "GOLDEN_CHESTPLATE", + "GOLDEN_LEGGINGS", + "GOLDEN_BOOTS", + "GOLD_BLOCK", + "GOLD_NUGGET", + "GOLDEN_AXE", + "GOLDEN_PICKAXE", + "GOLDEN_SHOVEL", + "GOLDEN_SWORD", + "GOLDEN_HOE", + "GOLDEN_HORSE_ARMOR", + "LIGHT_WEIGHTED_PRESSURE_PLATE", + "CLOCK", + "COMPASS", + "RAW_GOLD_BLOCK", + "RAW_IRON_BLOCK", + "RAW_IRON", + "RAW_GOLD", + "ANVIL", + "CHIPPED_ANVIL", + "DAMAGED_ANVIL", + "IRON_ORE", + "GOLD_ORE", + "DEEPSLATE_IRON_ORE", + "DEEPSLATE_GOLD_ORE", + "SHIELD" + )); + config.addDefault("Abilities.Earth.MagnetShield.Duration", 6000); + config.addDefault("Abilities.Earth.MagnetShield.Cooldowns.Shift", 5000); + config.addDefault("Abilities.Earth.MagnetShield.Cooldowns.Click", 5000); + config.addDefault("Abilities.Earth.MagnetShield.Range", 5.0); + config.addDefault("Abilities.Earth.MagnetShield.RepelArrows", true); + config.addDefault("Abilities.Earth.MagnetShield.RepelLivingEntities", true); + config.addDefault("Abilities.Earth.MagnetShield.Velocity", 0.1); + + config.addDefault("Abilities.Earth.MetalFragments.Enabled", true); + config.addDefault("Abilities.Earth.MetalFragments.Description", "MetalFragments allows you to select a source and shoot " + + "multiple fragments of metal out of that source " + + "block towards your target, injuring them on impact. " + + "To use, tap Sneak (Default: Shift) at a metal " + + "source block and it will float up. Then, turn around " + + "and click at your target to fling metal fragments at them."); + config.addDefault("Abilities.Earth.MetalFragments.Cooldown", 5000); + config.addDefault("Abilities.Earth.MetalFragments.MaxSources", 3); + config.addDefault("Abilities.Earth.MetalFragments.SourceRange", 5); + config.addDefault("Abilities.Earth.MetalFragments.MaxFragments", 10); + config.addDefault("Abilities.Earth.MetalFragments.Damage", 4.0); + config.addDefault("Abilities.Earth.MetalFragments.Velocity", 2.0); + + config.addDefault("Abilities.Earth.MetalHook.Enabled", true); + config.addDefault("Abilities.Earth.MetalHook.Description", "This ability lets a Metalbender bend metal into " + + "grappling hooks, allowing them to easily manouver terrain. " + + "To use this ability, the user must either have Iron in their inventory " + + "or be wearing an Iron/Chainmail Chestplate. Left-Click in the direction " + + "you are looking to fire a grappling hook, several hooks can be active at once, " + + "allowing the bender to 'hang' in locations. To disengage the hooks, hold Shift (Default: Sneak) or Sprint."); + config.addDefault("Abilities.Earth.MetalHook.Cooldown", 3000); + config.addDefault("Abilities.Earth.MetalHook.Range", 30); + config.addDefault("Abilities.Earth.MetalHook.MaxHooks", 3); + config.addDefault("Abilities.Earth.MetalHook.TotalHooks", 0); + config.addDefault("Abilities.Earth.MetalHook.RequireItems", true); + config.addDefault("Abilities.Earth.MetalHook.BarrierHooking", true); + + config.addDefault("Abilities.Earth.MetalShred.Enabled", true); + config.addDefault("Abilities.Earth.MetalShred.Description", "MetalShred allows you to tear a metal surface allowing you to sneak in to the other side." + + "To use, you must find a flat metal surface. Then, Sneak(Default: Shift) " + + "at a piece of metal on that surface, and two pieces of metal " + + "will be pulled toward you. Finally, run alongside the surface to coil " + + "the metal around those two pieces. The way will be open, and the blocks " + + "will not reset until you either select a new source or you switch " + + "abilities. If you click after having torn a hole in a vertical surface, " + + "you can Left-Click in any direction and the metal will unfold in that " + + "direction. If you are fast and precise enough, the metal can bend in " + + "any shape. The length of this sheet of metal depends on how much was " + + "coiled in the first place."); + config.addDefault("Abilities.Earth.MetalShred.SourceRange", 5); config.addDefault("Abilities.Earth.MetalShred.ExtendTick", 80); config.addDefault("Abilities.Earth.MetalShred.Damage", 6.0); - + config.addDefault("Abilities.Earth.MudSurge.Enabled", true); - config.addDefault("Abilities.Earth.MudSurge.Description", "This ability lets an earthbender send a surge of mud " - + "in any direction, knocking back enemies and " - + "dealing moderate damage. This ability has a chance " - + "of blinding the target. To use, select " - + "a source of earth and click in any direction."); - config.addDefault("Abilities.Earth.MudSurge.Cooldown", 6000); - config.addDefault("Abilities.Earth.MudSurge.Damage", 1.0); - config.addDefault("Abilities.Earth.MudSurge.Waves", 5); - config.addDefault("Abilities.Earth.MudSurge.SourceRange", 7); - config.addDefault("Abilities.Earth.MudSurge.BlindChance", 10); - config.addDefault("Abilities.Earth.MudSurge.WetSourceOnly", false); - config.addDefault("Abilities.Earth.MudSurge.WaterSearchRadius", 5); - config.addDefault("Abilities.Earth.MudSurge.BlindTicks", 60); - config.addDefault("Abilities.Earth.MudSurge.CollisionRadius", 2.0); - config.addDefault("Abilities.Earth.MudSurge.MultipleHits", true); - config.addDefault("Abilities.Earth.MudSurge.AllowFallDamage", false); - config.addDefault("Abilities.Earth.MudSurge.RemovalPolicy.SwappedSlots.Enabled", true); - config.addDefault("Abilities.Earth.MudSurge.RemovalPolicy.OutOfRange.Enabled", true); - config.addDefault("Abilities.Earth.MudSurge.RemovalPolicy.OutOfRange.Range", 25.0); - - config.addDefault("Abilities.Earth.SandBlast.Enabled", true); - config.addDefault("Abilities.Earth.SandBlast.Description", "This ability lets an earthbender blast a bunch of sand at an enemy " - + "damaging them and temporarily blinding them! Just Sneak (Default: Shift) " - + "on a sand bendable block, then Left-Click in a direction to shoot a " - + "blast of sand!"); - config.addDefault("Abilities.Earth.SandBlast.Cooldown", 3000); - config.addDefault("Abilities.Earth.SandBlast.Damage", 3.0); - config.addDefault("Abilities.Earth.SandBlast.SourceRange", 8); - config.addDefault("Abilities.Earth.SandBlast.Range", 30); - config.addDefault("Abilities.Earth.SandBlast.MaxSandBlocks", 10); - - config.addDefault("Abilities.Earth.EarthCombo.Crevice.Enabled", true); - config.addDefault("Abilities.Earth.EarthCombo.Crevice.Description", "Create a Crevice in the ground! Once opened, " - + "anyone can Tap Sneak with Shockwave to close the Crevice!"); - config.addDefault("Abilities.Earth.EarthCombo.Crevice.Range", 50); - config.addDefault("Abilities.Earth.EarthCombo.Crevice.RevertDelay", 7500); - config.addDefault("Abilities.Earth.EarthCombo.Crevice.Depth", 5); - config.addDefault("Abilities.Earth.EarthCombo.Crevice.AvatarStateDepth", 8); - config.addDefault("Abilities.Earth.EarthCombo.Crevice.Cooldown", 10000); - config.addDefault("Abilities.Earth.EarthCombo.Crevice.Combination", Arrays.asList("Collapse:RIGHT_CLICK_BLOCK", "Shockwave:SHIFT_DOWN", "Shockwave:SHIFT_UP", "Shockwave:SHIFT_DOWN")); - config.addDefault("Abilities.Earth.EarthCombo.Crevice.Instructions", "Collapse (Right-click a block) > Shockwave (Tap sneak) > Shockwave (Tap sneak)"); - - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Enabled", true); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Description", "Fire balls of magma at your enemy!"); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.MaxShots", 3); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.ImpactDamage", 2.0); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.SearchRange", 4); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Cooldown", 6000); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.ShotCooldown", 1500); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.RequireLavaFlow", false); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.PlayerCollisions", true); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.EntitySelection", true); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.SelectRange", 30.0); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.ExplosionRadius", 2.0); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.FireSpeed", 1.5); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.MaxDuration", 15000); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.MaxDistanceFromSources", 15); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Combination", Arrays.asList("EarthBlast:SHIFT_DOWN", "LavaFlow:SHIFT_UP", "LavaFlow:SHIFT_DOWN", "LavaFlow:RIGHT_CLICK_BLOCK")); - config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Instructions", "EarthBlast (Hold sneak) > LavaFlow (Release sneak) > LavaFlow (Hold sneak) > LavaFlow (Right-click a block) > LavaFlow (Left-click multiple times)"); - - config.addDefault("Abilities.Fire.Combustion.Enabled", true); - config.addDefault("Abilities.Fire.Combustion.Description", "Hold Shift to focus large amounts of energy into your body, " - + "Release Shift to fire Combustion. Move your mouse to " - + "direct where the beam travels. Left-Click to detonate " - + "the beam manually"); - config.addDefault("Abilities.Fire.Combustion.Damage", 4.0); - config.addDefault("Abilities.Fire.Combustion.FireTick", 100); - config.addDefault("Abilities.Fire.Combustion.MisfireModifier", -1); - config.addDefault("Abilities.Fire.Combustion.Power", 3); - config.addDefault("Abilities.Fire.Combustion.Range", 100); - config.addDefault("Abilities.Fire.Combustion.Speed", 0.65); - config.addDefault("Abilities.Fire.Combustion.Warmup", 1500); - config.addDefault("Abilities.Fire.Combustion.Cooldown", 5000); - config.addDefault("Abilities.Fire.Combustion.RegenTime", 10000); - config.addDefault("Abilities.Fire.Combustion.EntityCollisionRadius", 1.3); - config.addDefault("Abilities.Fire.Combustion.AbilityCollisionRadius", 1.3); - config.addDefault("Abilities.Fire.Combustion.DamageBlocks", true); - config.addDefault("Abilities.Fire.Combustion.RegenBlocks", true); - config.addDefault("Abilities.Fire.Combustion.WaitForRegen", true); - config.addDefault("Abilities.Fire.Combustion.InstantExplodeIfHit", true); - config.addDefault("Abilities.Fire.Combustion.ExplodeOnDeath", true); - config.addDefault("Abilities.Fire.Combustion.RemovalPolicy.SwappedSlots.Enabled", false); - - config.addDefault("Abilities.Fire.Discharge.Enabled", true); - config.addDefault("Abilities.Fire.Discharge.Description", "Left-Click to shoot bolts of electricity out " - + "of your fingertips zapping what ever it hits!"); - config.addDefault("Abilities.Fire.Discharge.Damage", 3.0); - config.addDefault("Abilities.Fire.Discharge.Cooldown", 5000); - config.addDefault("Abilities.Fire.Discharge.AvatarCooldown", 500); - config.addDefault("Abilities.Fire.Discharge.Duration", 1000); - config.addDefault("Abilities.Fire.Discharge.SlotSwapping", false); - config.addDefault("Abilities.Fire.Discharge.EntityCollisionRadius", 1.0); - config.addDefault("Abilities.Fire.Discharge.AbilityCollisionRadius", 1.0); - - config.addDefault("Abilities.Fire.FireBall.Enabled", true); - config.addDefault("Abilities.Fire.FireBall.Description", "To use, simply Left-Click to shoot a fireball at your target!"); - config.addDefault("Abilities.Fire.FireBall.Cooldown", 3000); - config.addDefault("Abilities.Fire.FireBall.Range", 50); - config.addDefault("Abilities.Fire.FireBall.Damage", 3.0); - config.addDefault("Abilities.Fire.FireBall.FireDuration", 2000); - config.addDefault("Abilities.Fire.FireBall.Controllable", false); - config.addDefault("Abilities.Fire.FireBall.FireTrail", true); - config.addDefault("Abilities.Fire.FireBall.CollisionRadius", 1.1); - config.addDefault("Abilities.Fire.FireBall.Collisions.FireShield.Enabled", true); - config.addDefault("Abilities.Fire.FireBall.Collisions.FireShield.RemoveFirst", true); - config.addDefault("Abilities.Fire.FireBall.Collisions.FireShield.RemoveSecond", false); - config.addDefault("Abilities.Fire.FireBall.Collisions.AirShield.Enabled", true); - config.addDefault("Abilities.Fire.FireBall.Collisions.AirShield.RemoveFirst", false); - config.addDefault("Abilities.Fire.FireBall.Collisions.AirShield.RemoveSecond", false); - config.addDefault("Abilities.Fire.FireBall.Collisions.AirShield.Reflect", true); - - config.addDefault("Abilities.Fire.FireBreath.Enabled", true); - config.addDefault("Abilities.Fire.FireBreath.Description", "To use, hold Sneak (Default: Shift) to start breathing " - + "fire! Some Firebenders possess the power to infuse color " - + "when they breathe, it's unclear how they do this, but some suggest " - + "it can be obtained by saying \"Bring fire and light together as one and allow the breath of color\" " - + "and can be brought back to normal by saying \"Split the bond of fire " - + "and light and set the color free\"."); - config.addDefault("Abilities.Fire.FireBreath.Cooldown", 5000); - config.addDefault("Abilities.Fire.FireBreath.Duration", 3000); - config.addDefault("Abilities.Fire.FireBreath.Particles", 3); - config.addDefault("Abilities.Fire.FireBreath.Damage.Player", 1.0); - config.addDefault("Abilities.Fire.FireBreath.Damage.Mob", 2.0); - config.addDefault("Abilities.Fire.FireBreath.FireDuration", 3000); - config.addDefault("Abilities.Fire.FireBreath.Range", 10); - config.addDefault("Abilities.Fire.FireBreath.Avatar.FireEnabled", true); - config.addDefault("Abilities.Fire.FireBreath.Melt.Enabled", true); - config.addDefault("Abilities.Fire.FireBreath.Melt.Chance", 3); - config.addDefault("Abilities.Fire.FireBreath.RainbowBreath.Enabled", true); - config.addDefault("Abilities.Fire.FireBreath.RainbowBreath.EnabledMessage", "You have bonded fire with light and can now breathe pure color."); - config.addDefault("Abilities.Fire.FireBreath.RainbowBreath.DisabledMessage", "You have split your bond of color and light."); - config.addDefault("Abilities.Fire.FireBreath.RainbowBreath.NoAccess", "You don't possess the power to bond light with fire."); - - config.addDefault("Abilities.Fire.FireComet.Enabled", true); - config.addDefault("Abilities.Fire.FireComet.Description", "Harnessing the power of Sozin's Comet, a firebender can create a great " - + "ball of fire, with much destructive power. Only useable during Sozin's Comet or while in the AvatarState, hold Sneak (Default: Shift) " - + "to start charging the ability up. Once the ability is charged, a large mass of particles will follow your cursor, until you release sneak, " - + "launching the great ball of fire in the direction you are looking."); - config.addDefault("Abilities.Fire.FireComet.Cooldown", 45000); - config.addDefault("Abilities.Fire.FireComet.ChargeUp", 7000); - config.addDefault("Abilities.Fire.FireComet.Damage", 6.0); - config.addDefault("Abilities.Fire.FireComet.BlastRadius", 3.0); - config.addDefault("Abilities.Fire.FireComet.SozinsComet.Cooldown", 30000); - config.addDefault("Abilities.Fire.FireComet.SozinsComet.ChargeUp", 5000); - config.addDefault("Abilities.Fire.FireComet.SozinsComet.Damage", 12.0); - config.addDefault("Abilities.Fire.FireComet.SozinsComet.BlastRadius", 5.0); - config.addDefault("Abilities.Fire.FireComet.Range", 50); - config.addDefault("Abilities.Fire.FireComet.RegenDelay", 15000); - config.addDefault("Abilities.Fire.FireComet.SozinsCometOnly", true); - config.addDefault("Abilities.Fire.FireComet.AvatarStateBypassComet", true); - - config.addDefault("Abilities.Fire.FirePunch.Enabled", true); - config.addDefault("Abilities.Fire.FirePunch.Description", "This basic ability allows a Firebender to channel their energies into a " - + "single punch, igniting and damaging the victim."); - config.addDefault("Abilities.Fire.FirePunch.Cooldown", 4000); - config.addDefault("Abilities.Fire.FirePunch.FireTicks", 2000); - config.addDefault("Abilities.Fire.FirePunch.Damage", 2.0); - - config.addDefault("Abilities.Fire.FireShots.Enabled", true); - config.addDefault("Abilities.Fire.FireShots.Description", "To use, tap Sneak (Default: Shift) to summon a " - + "FireBalls at your hand, then Left Click to shoot off each ball! " - + "Each shot will follow the cursor until it runs out or hits something! " - + "Tap Sneak again to switch your main hand."); - config.addDefault("Abilities.Fire.FireShots.Cooldown", 3000); - config.addDefault("Abilities.Fire.FireShots.Range", 50); - config.addDefault("Abilities.Fire.FireShots.FireBalls", 4); - config.addDefault("Abilities.Fire.FireShots.FireDuration", 3000); - config.addDefault("Abilities.Fire.FireShots.Damage", 2.0); - config.addDefault("Abilities.Fire.FireShots.CollisionRadius", 0.9); - config.addDefault("Abilities.Fire.FireShots.Collisions.FireShield.Enabled", true); - config.addDefault("Abilities.Fire.FireShots.Collisions.FireShield.RemoveFirst", true); - config.addDefault("Abilities.Fire.FireShots.Collisions.FireShield.RemoveSecond", false); - config.addDefault("Abilities.Fire.FireShots.Collisions.AirShield.Enabled", true); - config.addDefault("Abilities.Fire.FireShots.Collisions.AirShield.RemoveFirst", false); - config.addDefault("Abilities.Fire.FireShots.Collisions.AirShield.RemoveSecond", false); - config.addDefault("Abilities.Fire.FireShots.Collisions.AirShield.Reflect", true); - - config.addDefault("Abilities.Fire.FireSki.Enabled", true); - config.addDefault("Abilities.Fire.FireSki.Cooldown", 6000); - config.addDefault("Abilities.Fire.FireSki.Duration", 6000); - config.addDefault("Abilities.Fire.FireSki.Speed", 0.7); - config.addDefault("Abilities.Fire.FireSki.IgniteEntities", true); - config.addDefault("Abilities.Fire.FireSki.FireTicks", 60); - config.addDefault("Abilities.Fire.FireSki.RequiredHeight", 0.7); - config.addDefault("Abilities.Fire.FireSki.PunchActivated", false); - - config.addDefault("Abilities.Fire.LightningBurst.Enabled", true); - config.addDefault("Abilities.Fire.LightningBurst.Description", "To use the most explosive lightning move available to a firebender, hold " - + "Sneak (Default: Shift) until blue sparks appear in front of you. Upon releasing, " - + "you will unleash an electrical sphere, shocking anyone who gets too close"); - config.addDefault("Abilities.Fire.LightningBurst.Cooldown", 25000); - config.addDefault("Abilities.Fire.LightningBurst.ChargeUp", 4000); - config.addDefault("Abilities.Fire.LightningBurst.AvatarCooldown", 1000); - config.addDefault("Abilities.Fire.LightningBurst.AvatarChargeUp", 1000); - config.addDefault("Abilities.Fire.LightningBurst.Radius", 12); - config.addDefault("Abilities.Fire.LightningBurst.Damage", 9.0); - - config.addDefault("Abilities.Water.Bloodbending.Enabled", true); - config.addDefault("Abilities.Water.Bloodbending.Description", "This ability allows a skilled waterbender " - + "to bend the water within an enemy's blood, granting them full " - + "control over the enemy's limbs. This ability is extremely dangerous " - + "and is to be used carefully. To use, sneak while looking at an entity " - + "and its body will follow your movement. If you click, you will launch " - + "the entity towards whatever you were looking at when you clicked. The " - + "entity may collide with others, injuring them and the other one further."); - config.addDefault("Abilities.Water.Bloodbending.NightOnly", false); - config.addDefault("Abilities.Water.Bloodbending.FullMoonOnly", false); - config.addDefault("Abilities.Water.Bloodbending.UndeadMobs", true); - config.addDefault("Abilities.Water.Bloodbending.IgnoreWalls", false); - config.addDefault("Abilities.Water.Bloodbending.RequireBound", false); - config.addDefault("Abilities.Water.Bloodbending.Distance", 6); - config.addDefault("Abilities.Water.Bloodbending.HoldTime", 10000); - config.addDefault("Abilities.Water.Bloodbending.Cooldown", 4000); - - config.addDefault("Abilities.Water.BloodPuppet.Enabled", true); - config.addDefault("Abilities.Water.BloodPuppet.Description", "This very high-level bloodbending ability lets " - + "a master control entities' limbs, forcing them to " - + "attack the master's target. To use this ability, you must " - + "be a bloodbender. Next, sneak while targeting " - + "a mob or player and you will start controlling them. To " - + "make the entity hit another, click. To release your " - + "target, stop sneaking. This ability has NO cooldown, but " - + "may only be usable during the night depending on the " - + "server configuration."); - config.addDefault("Abilities.Water.BloodPuppet.NightOnly", false); - config.addDefault("Abilities.Water.BloodPuppet.FullMoonOnly", false); - config.addDefault("Abilities.Water.BloodPuppet.UndeadMobs", true); - config.addDefault("Abilities.Water.BloodPuppet.IgnoreWalls", false); - config.addDefault("Abilities.Water.BloodPuppet.RequireBound", false); - config.addDefault("Abilities.Water.BloodPuppet.Distance", 6); - config.addDefault("Abilities.Water.BloodPuppet.HoldTime", 10000); - config.addDefault("Abilities.Water.BloodPuppet.Cooldown", 4000); - - config.addDefault("Abilities.Water.Drain.Enabled", true); - config.addDefault("Abilities.Water.Drain.Description", "Inspired by how Hama drained water from the fire lilies, many benders " - + "have practiced in the skill of draining water from plants! With this ability bound, " - + "Sneak (Default: Shift) near/around plant sources to drain the water out of them to fill up any " - + "bottles/buckets in your inventory! Alternatively, if you have nothing to fill" - + " and blasts are enabled in the config, you will be able to create mini blasts " - + "of water to shoot at your targets! Aleternatively, this ability can also be used to quickly fill up " - + "bottles from straight water sources or from falling rain!"); - config.addDefault("Abilities.Water.Drain.RegenDelay", 15000); - config.addDefault("Abilities.Water.Drain.Duration", 2000); - config.addDefault("Abilities.Water.Drain.Cooldown", 2000); - config.addDefault("Abilities.Water.Drain.AbsorbSpeed", 0.1); - config.addDefault("Abilities.Water.Drain.AbsorbChance", 20); - config.addDefault("Abilities.Water.Drain.AbsorbRate", 6); - config.addDefault("Abilities.Water.Drain.Radius", 6); - config.addDefault("Abilities.Water.Drain.HoldRange", 2); - config.addDefault("Abilities.Water.Drain.AllowRainSource", true); - config.addDefault("Abilities.Water.Drain.BlastsEnabled", true); - config.addDefault("Abilities.Water.Drain.KeepSource", false); - config.addDefault("Abilities.Water.Drain.BlastSpeed", 1); - config.addDefault("Abilities.Water.Drain.BlastDamage", 1.5); - config.addDefault("Abilities.Water.Drain.BlastRange", 20); - config.addDefault("Abilities.Water.Drain.MaxBlasts", 4); - config.addDefault("Abilities.Water.Drain.DrainTempBlocks", true); - - config.addDefault("Abilities.Water.FrostBreath.Enabled", true); - config.addDefault("Abilities.Water.FrostBreath.Description", "As demonstrated by Katara, a Waterbender is able to freeze their breath, " - + "causing anything it touches to be frozen! With this ability bound, simply hold " - + "Sneak (Default: Shift) to start breathing frost!"); - config.addDefault("Abilities.Water.FrostBreath.Cooldown", 15000); - config.addDefault("Abilities.Water.FrostBreath.Duration", 3000); - config.addDefault("Abilities.Water.FrostBreath.Particles", 3); - config.addDefault("Abilities.Water.FrostBreath.FrostDuration", 5000); - config.addDefault("Abilities.Water.FrostBreath.FrozenWaterDuration", 10000); - config.addDefault("Abilities.Water.FrostBreath.Range", 10); - config.addDefault("Abilities.Water.FrostBreath.Snow", true); - config.addDefault("Abilities.Water.FrostBreath.SnowDuration", 5000); - config.addDefault("Abilities.Water.FrostBreath.BendableSnow", false); - config.addDefault("Abilities.Water.FrostBreath.Damage.Enabled", false); - config.addDefault("Abilities.Water.FrostBreath.Damage.Player", 1.0); - config.addDefault("Abilities.Water.FrostBreath.Damage.Mob", 2.0); - config.addDefault("Abilities.Water.FrostBreath.Slow.Enabled", true); - config.addDefault("Abilities.Water.FrostBreath.Slow.Duration", 4000); - config.addDefault("Abilities.Water.FrostBreath.RestrictBiomes", true); - - config.addDefault("Abilities.Water.HealingWaters.Enabled", true); - config.addDefault("Abilities.Water.HealingWaters.Description", "To use this ability, the bender has to be partially submerged " - + "in water, OR be holding either a bottle of water or a water bucket." - + " This move will heal the player automatically if they have it equipped " - + "and are standing in water. If the player sneaks while in water and is targeting" - + " another entity, the bender will heal the targeted entity. The alternate " - + "healing method requires the bender to be holding a bottle of water or a water" - + " bucket. To start healing simply sneak, however if the bender is targeting " - + "a mob while sneaking, the bender will heal the targeted mob."); - config.addDefault("Abilities.Water.HealingWaters.Power", 1); - config.addDefault("Abilities.Water.HealingWaters.Range", 5); - config.addDefault("Abilities.Water.HealingWaters.DrainChance", 5); - config.addDefault("Abilities.Water.HealingWaters.DynamicLight.Enabled", true); - config.addDefault("Abilities.Water.HealingWaters.DynamicLight.Brightness", 10); - config.addDefault("Abilities.Water.HealingWaters.DynamicLight.KeepAlive", 1500); - - config.addDefault("Abilities.Water.IceClaws.Enabled", true); - config.addDefault("Abilities.Water.IceClaws.Description", "As demonstrated by Hama, a Waterbender can pull water out of thin air to create claws " - + "at the tips of their fingers. With IceClaws bound, hold Sneak (Default: Shift) to " - + "start pulling water out the air until you form claws at your finger " - + "tips, then attack an enemy to slow them down and do a bit of damage!"); - config.addDefault("Abilities.Water.IceClaws.Cooldown", 6000); - config.addDefault("Abilities.Water.IceClaws.ChargeTime", 1000); - config.addDefault("Abilities.Water.IceClaws.SlowDuration", 5000); - config.addDefault("Abilities.Water.IceClaws.Damage", 3.0); - config.addDefault("Abilities.Water.IceClaws.Range", 10); - config.addDefault("Abilities.Water.IceClaws.Throwable", true); - - config.addDefault("Abilities.Water.IceWall.Enabled", true); - config.addDefault("Abilities.Water.IceWall.Description", "IceWall allows an icebender to create a wall of ice, similar to " - + "raiseearth. To use, simply sneak while targeting either water, ice, or snow. " - + "To break the wall, you must sneak again while targeting it. Be aware that " - + "other icebenders can break your own shields, and if you are too close you " - + "can get hurt by the shards."); - config.addDefault("Abilities.Water.IceWall.Cooldown", 4000); - config.addDefault("Abilities.Water.IceWall.Width", 6); - config.addDefault("Abilities.Water.IceWall.MaxHeight", 5); - config.addDefault("Abilities.Water.IceWall.MinHeight", 3); - config.addDefault("Abilities.Water.IceWall.MaxWallHealth", 12); - config.addDefault("Abilities.Water.IceWall.MinWallHealth", 8); - config.addDefault("Abilities.Water.IceWall.Range", 8); - config.addDefault("Abilities.Water.IceWall.Damage", 4.0); - config.addDefault("Abilities.Water.IceWall.CanBreak", true); - config.addDefault("Abilities.Water.IceWall.Stackable", false); - config.addDefault("Abilities.Water.IceWall.LifeTime.Enabled", false); - config.addDefault("Abilities.Water.IceWall.LifeTime.Duration", 10000); - config.addDefault("Abilities.Water.IceWall.WallDamage", true); - config.addDefault("Abilities.Water.IceWall.WallDamage.Torrent", 5); - config.addDefault("Abilities.Water.IceWall.WallDamage.TorrentFreeze", 9); - config.addDefault("Abilities.Water.IceWall.WallDamage.IceBlast", 8); - config.addDefault("Abilities.Water.IceWall.WallDamage.Fireblast", 3); - config.addDefault("Abilities.Water.IceWall.WallDamage.FireblastCharged", 5); - config.addDefault("Abilities.Water.IceWall.WallDamage.Lightning", 12); - config.addDefault("Abilities.Water.IceWall.WallDamage.Combustion", 12); - config.addDefault("Abilities.Water.IceWall.WallDamage.EarthSmash", 8); - config.addDefault("Abilities.Water.IceWall.WallDamage.AirBlast", 2); - - config.addDefault("Abilities.Water.WakeFishing.Enabled", true); - config.addDefault("Abilities.Water.WakeFishing.Description", "With this ability bound, hold Sneak (Default: Shift) at a water block and " - + "don't lose focus of that block. Eventually some fish will investigate " - + "the wake and swim out at you!"); - config.addDefault("Abilities.Water.WakeFishing.Cooldown", 10000); - config.addDefault("Abilities.Water.WakeFishing.Duration", 20000); - config.addDefault("Abilities.Water.WakeFishing.Range", 5); - - config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Enabled", true); - config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Description", "Create a swirling mass of water that drags any entity that enters it to the bottom " - + "of the whirlpool."); - config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Cooldown", 25000); - config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Duration", 15000); - config.addDefault("Abilities.Water.WaterCombo.Maelstrom.MaxDepth", 5); - config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Range", 10); - config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Combination", Arrays.asList("PhaseChange:SHIFT_DOWN", "Torrent:LEFT_CLICK", "Torrent:LEFT_CLICK")); - config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Instructions", "PhaseChange (Hold sneak) > Torrent (Left-click) > Torrent (Left-click)"); - - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Enabled", true); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Description", "Some Waterbenders have managed to create torrents of water much stronger than a regular torrent, " - + "that can carry them selves and others, as well as being able to freeze the entire stream whenever. The bender must stay focused on the flow or else the flow will stop." - + " If you Sneak (Default: Shift) while controlling the stream, the stream will return to you."); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Cooldown", 8000); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Duration", 8000); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.MeltDelay", 5000); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.SourceRange", 10); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.MaxRange", 40); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.MinRange", 8); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Trail", 80); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.BottleSource", false); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.PlantSource", false); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.RemoveOnAnyDamage", false); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Size.Normal", 1); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Size.AvatarState", 3); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Size.FullmoonSmall", 2); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Size.FullmoonLarge", 3); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.IsAvatarStateToggle", true); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.AvatarStateDuration", 60000); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.PlayerStayNearSource", true); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.MaxDistanceFromSource", 100); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.FullMoon.Enabled", true); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.FullMoon.Modifier.Cooldown", 3); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.FullMoon.Modifier.Duration", 2); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.PlayerRideOwnFlow", true); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Combination", Arrays.asList("WaterManipulation:SHIFT_DOWN", "WaterManipulation:SHIFT_UP", "Torrent:SHIFT_DOWN", "Torrent:SHIFT_UP", "Torrent:SHIFT_DOWN", "WaterManipulation:SHIFT_UP")); - config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Instructions", "WaterManipulation (Tap sneak) > Torrent (Tap sneak) > Torrent (Hold sneak) > WaterManipulation (Release sneak)"); - - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Enabled", true); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Description", "Skilled Waterbenders are able to create two spinning rings of water around their bodies, " - + "which can be used as a defensive ability or for an offensive attack."); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Cooldown", 7000); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Damage", 3.0); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.RingSize", 3.5); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Range", 40); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.SourceRange", 10); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Speed", 2); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.AnimationSpeed", 3); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.PlantSource", true); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.SnowSource", true); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.RequireAdjacentPlants", true); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.BottleSource", false); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.AbilityCollisionRadius", 1.6); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.EntityCollisionRadius", 1.6); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Collisions.FireShield.Enabled", false); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Collisions.FireShield.RemoveFirst", true); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Collisions.FireShield.RemoveSecond", false); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Combination", Arrays.asList("Torrent:SHIFT_DOWN", "Torrent:SHIFT_UP", "Torrent:SHIFT_DOWN", "Torrent:SHIFT_UP", "WaterManipulation:SHIFT_DOWN")); - config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Instructions", "Torrent (Tap sneak) > Torrent (Tap sneak) > WaterManipulation (Hold sneak) > WaterManipulation (Left-click multiple times)"); - - config.addDefault("Abilities.Water.Ice.Passive.Skate.Enabled", true); - config.addDefault("Abilities.Water.Ice.Passive.Skate.SpeedFactor", 4); - - config.addDefault("Abilities.Chi.Backstab.Enabled", true); - config.addDefault("Abilities.Chi.Backstab.Description", "Strike your foe in the back with a hard jab, temporariliy blocking their Chi, and " - + "inflicting a lot of damage! This ability has a long cooldown. You must hit the target in the back or this ability won't work!"); - config.addDefault("Abilities.Chi.Backstab.Cooldown", 8500); - config.addDefault("Abilities.Chi.Backstab.Damage", 6.0); - config.addDefault("Abilities.Chi.Backstab.MaxActivationAngle", 90); - - config.addDefault("Abilities.Chi.DaggerThrow.Enabled", true); - config.addDefault("Abilities.Chi.DaggerThrow.Description", "With this ability bound, Left-Click in " - + "rapid succession to shoot arrows out of your inventory at your target!"); - config.addDefault("Abilities.Chi.DaggerThrow.Cooldown", 3000); - config.addDefault("Abilities.Chi.DaggerThrow.MaxDaggers.Enabled", true); - config.addDefault("Abilities.Chi.DaggerThrow.MaxDaggers.Amount", 6); - config.addDefault("Abilities.Chi.DaggerThrow.Damage", 1.0); - config.addDefault("Abilities.Chi.DaggerThrow.ParticleTrail", true); - config.addDefault("Abilities.Chi.DaggerThrow.AbilityCollisionRadius", 0.5); - config.addDefault("Abilities.Chi.DaggerThrow.Interactions.WaterSpout.Enabled", true); - config.addDefault("Abilities.Chi.DaggerThrow.Interactions.WaterSpout.Cooldown", 1000); - config.addDefault("Abilities.Chi.DaggerThrow.Interactions.WaterSpout.HitsRequired", 1); - config.addDefault("Abilities.Chi.DaggerThrow.Interactions.AirSpout.Enabled", true); - config.addDefault("Abilities.Chi.DaggerThrow.Interactions.AirSpout.Cooldown", 1000); - config.addDefault("Abilities.Chi.DaggerThrow.Interactions.AirSpout.HitsRequired", 1); - - String[] invalidWallRun = {Material.BARRIER.name()}; - config.addDefault("Abilities.Passives.WallRun.Enabled", true); - config.addDefault("Abilities.Passives.WallRun.Cooldown", 6000); - config.addDefault("Abilities.Passives.WallRun.Duration", 20000); - config.addDefault("Abilities.Passives.WallRun.Particles", true); - config.addDefault("Abilities.Passives.WallRun.Air", true); - config.addDefault("Abilities.Passives.WallRun.Earth", false); - config.addDefault("Abilities.Passives.WallRun.Water", false); - config.addDefault("Abilities.Passives.WallRun.Fire", true); - config.addDefault("Abilities.Passives.WallRun.Chi", true); - config.addDefault("Abilities.Passives.WallRun.InvalidBlocks", invalidWallRun); - - config.options().copyDefaults(true); - plugin.saveConfig(); - } - - private void addDeathMessages() { - FileConfiguration lang = ConfigManager.languageConfig.get(); - - //Fire - lang.addDefault("Abilities.Fire.FireComet.DeathMessage", "{victim} was squashed under the pressure of {attacker}'s {ability}"); - lang.addDefault("Abilities.Fire.FireBall.DeathMessage", "{victim} burst from {attacker}'s {ability}"); - lang.addDefault("Abilities.Fire.FireBreath.DeathMessage", "{victim} was consumed {attacker}'s {ability}"); - lang.addDefault("Abilities.Fire.Discharge.DeathMessage", "{victim} couldn't take {attacker}'s {ability}"); - lang.addDefault("Abilities.Fire.FirePunch.DeathMessage", "{victim} punched out from {attacker}'s {ability}"); - lang.addDefault("Abilities.Fire.FireShots.DeathMessage", "{victim} was shot by {attacker}'s {ability}"); - lang.addDefault("Abilities.Fire.LightningBurst.DeathMessage", "{victim} crackled out of existence from {attacker}'s {ability}"); - - //Water - lang.addDefault("Abilities.Water.Drain.DeathMessage", "{victim} was blasted by {attacker}'s {ability}"); - lang.addDefault("Abilities.Water.FrostBreath.DeathMessage", "{victim} shattered from {attacker}'s {ability}"); - lang.addDefault("Abilities.Water.IceClaws.DeathMessage", "{victim} was ripped to shreds by {attacker}'s {ability}"); - lang.addDefault("Abilities.Water.IceWall.DeathMessage", "{victim} was collateral to {attacker}'s exploding {ability}"); - lang.addDefault("Abilities.Water.WaterBlast.DeathMessage", "{victim} was blasted by {attacker}'s {ability}"); - lang.addDefault("Abilities.Water.Combo.WaterGimbal.DeathMessage", "{victim} was ripped apart by {attacker}'s {ability}"); - - //Earth - lang.addDefault("Abilities.Earth.EarthKick.DeathMessage", "{victim} got too much dirt in their eye from {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.EarthLine.DeathMessage", "{victim} lost their footing from {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.EarthShard.DeathMessage", "{victim} got blasted apart {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.LavaDisc.DeathMessage", "{victim} sliced in half by {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.LavaFlux.DeathMessage", "{victim} couldn't take the heat from {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.LavaThrow.DeathMessage", "{victim} melted from {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.MetalFragments.DeathMessage", "{victim} was shredded apart from {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.MetalShred.DeathMessage", "{victim} was in the way of {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.MudSurge.DeathMessage", "{victim} drowned in mud from {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.SandBlast.DeathMessage", "{victim} was sandblasted to oblivion from {attacker}'s {ability}"); - lang.addDefault("Abilities.Earth.Combo.MagmaBlast.DeathMessage", "{victim} was obliterated by {attacker}'s {ability}"); - - //Air - lang.addDefault("Abilities.Air.AirBlade.DeathMessage", "{victim} was sliced in two by {attacker}'s {ability}"); - lang.addDefault("Abilities.Air.AirPunch.DeathMessage", "{victim} was exploded from {attacker}'s {ability}"); - lang.addDefault("Abilities.Air.SonicBlast.DeathMessage", "{victim}'s ears burst from {attacker}'s {ability}"); - - //Chi - lang.addDefault("Abilities.Chi.DaggerThrow.DeathMessage", "{victim} got stabbed too many times from {attacker}'s {ability}"); - lang.addDefault("Abilities.Chi.Backstab.DeathMessage", "{victim} fell victim to {attacker}'s {ability}"); - - //Avatar - lang.addDefault("Abilities.Avatar.SpiritBeam.DeathMessage", "{victim} was erased from existence by {attacker}'s {ability}"); - lang.addDefault("Abilities.Avatar.ElementSphereAir.DeathMessage", "{victim} was blasted apart by {attacker}'s \u00A75ElementSphere"); - lang.addDefault("Abilities.Avatar.ElementSphereFire.DeathMessage", "{victim} was burnt to cinders by {attacker}'s \u00A75ElementSphere"); - lang.addDefault("Abilities.Avatar.ElementSphereEarth.DeathMessage", "{victim} was crushed by {attacker}'s \u00A75ElementSphere"); - lang.addDefault("Abilities.Avatar.ElementSphereWater.DeathMessage", "{victim} was sliced apart by {attacker}'s \u00A75ElementSphere"); - lang.addDefault("Abilities.Avatar.ElementSphereStream.DeathMessage", "{victim} took the full force of {attacker}'s \u00A75ElementSphere"); - - ConfigManager.languageConfig.save(); - } - - private void setupElementSphereNames() { - FileConfiguration lang = ConfigManager.languageConfig.get(); - - lang.addDefault("Abilities.Avatar.ElementSphereAir.Name", "Air"); - lang.addDefault("Abilities.Avatar.ElementSphereFire.Name", "Fire"); - lang.addDefault("Abilities.Avatar.ElementSphereEarth.Name", "Earth"); - lang.addDefault("Abilities.Avatar.ElementSphereWater.Name", "Water"); - lang.addDefault("Abilities.Avatar.ElementSphereStream.Name", "Stream"); - - ConfigManager.languageConfig.save(); - } - - public static ConfigurationSection getConfig(Player player) { - if (player == null) - return getConfig((World)null); - return getConfig(player.getWorld()); - } - - public static ConfigurationSection getConfig(World world) { - boolean perWorldConfig = plugin.getConfig().getBoolean("Properties.PerWorldConfig"); - - if (world == null || !perWorldConfig) { - return plugin.getConfig(); - } - - String prefix = "Worlds." + world.getName(); - return new SubsectionConfigurationDecorator(plugin.getConfig(), prefix); - } -} + config.addDefault("Abilities.Earth.MudSurge.Description", "This ability lets an earthbender send a surge of mud " + + "in any direction, knocking back enemies and " + + "dealing moderate damage. This ability has a chance " + + "of blinding the target. To use, select " + + "a source of earth and click in any direction."); + config.addDefault("Abilities.Earth.MudSurge.Cooldown", 6000); + config.addDefault("Abilities.Earth.MudSurge.Damage", 1.0); + config.addDefault("Abilities.Earth.MudSurge.Waves", 5); + config.addDefault("Abilities.Earth.MudSurge.SourceRange", 7); + config.addDefault("Abilities.Earth.MudSurge.BlindChance", 10); + config.addDefault("Abilities.Earth.MudSurge.WetSourceOnly", false); + config.addDefault("Abilities.Earth.MudSurge.WaterSearchRadius", 5); + config.addDefault("Abilities.Earth.MudSurge.BlindTicks", 60); + config.addDefault("Abilities.Earth.MudSurge.CollisionRadius", 2.0); + config.addDefault("Abilities.Earth.MudSurge.MultipleHits", true); + config.addDefault("Abilities.Earth.MudSurge.AllowFallDamage", false); + config.addDefault("Abilities.Earth.MudSurge.RemovalPolicy.SwappedSlots.Enabled", true); + config.addDefault("Abilities.Earth.MudSurge.RemovalPolicy.OutOfRange.Enabled", true); + config.addDefault("Abilities.Earth.MudSurge.RemovalPolicy.OutOfRange.Range", 25.0); + + config.addDefault("Abilities.Earth.SandBlast.Enabled", true); + config.addDefault("Abilities.Earth.SandBlast.Description", "This ability lets an earthbender blast a bunch of sand at an enemy " + + "damaging them and temporarily blinding them! Just Sneak (Default: Shift) " + + "on a sand bendable block, then Left-Click in a direction to shoot a " + + "blast of sand!"); + config.addDefault("Abilities.Earth.SandBlast.Cooldown", 3000); + config.addDefault("Abilities.Earth.SandBlast.Damage", 3.0); + config.addDefault("Abilities.Earth.SandBlast.SourceRange", 8); + config.addDefault("Abilities.Earth.SandBlast.Range", 30); + config.addDefault("Abilities.Earth.SandBlast.MaxSandBlocks", 10); + + config.addDefault("Abilities.Earth.EarthCombo.Crevice.Enabled", true); + config.addDefault("Abilities.Earth.EarthCombo.Crevice.Description", "Create a Crevice in the ground! Once opened, " + + "anyone can Tap Sneak with Shockwave to close the Crevice!"); + config.addDefault("Abilities.Earth.EarthCombo.Crevice.Range", 50); + config.addDefault("Abilities.Earth.EarthCombo.Crevice.RevertDelay", 7500); + config.addDefault("Abilities.Earth.EarthCombo.Crevice.Depth", 5); + config.addDefault("Abilities.Earth.EarthCombo.Crevice.AvatarStateDepth", 8); + config.addDefault("Abilities.Earth.EarthCombo.Crevice.Cooldown", 10000); + config.addDefault("Abilities.Earth.EarthCombo.Crevice.Combination", Arrays.asList("Collapse:RIGHT_CLICK_BLOCK", "Shockwave:SHIFT_DOWN", "Shockwave:SHIFT_UP", "Shockwave:SHIFT_DOWN")); + config.addDefault("Abilities.Earth.EarthCombo.Crevice.Instructions", "Collapse (Right-click a block) > Shockwave (Tap sneak) > Shockwave (Tap sneak)"); + + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Enabled", true); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Description", "Fire balls of magma at your enemy!"); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.MaxShots", 3); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.ImpactDamage", 2.0); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.SearchRange", 4); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Cooldown", 6000); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.ShotCooldown", 1500); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.RequireLavaFlow", false); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.PlayerCollisions", true); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.EntitySelection", true); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.SelectRange", 30.0); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.ExplosionRadius", 2.0); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.FireSpeed", 1.5); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.MaxDuration", 15000); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.MaxDistanceFromSources", 15); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Combination", Arrays.asList("EarthBlast:SHIFT_DOWN", "LavaFlow:SHIFT_UP", "LavaFlow:SHIFT_DOWN", "LavaFlow:RIGHT_CLICK_BLOCK")); + config.addDefault("Abilities.Earth.EarthCombo.MagmaBlast.Instructions", "EarthBlast (Hold sneak) > LavaFlow (Release sneak) > LavaFlow (Hold sneak) > LavaFlow (Right-click a block) > LavaFlow (Left-click multiple times)"); + + ArrayList combustionSkipMaterials = new ArrayList<>(); + combustionSkipMaterials.add("#bee_growables"); + combustionSkipMaterials.add("#cave_vines"); + combustionSkipMaterials.add("#crops"); + combustionSkipMaterials.add("#flowers"); + combustionSkipMaterials.add("vine"); + combustionSkipMaterials.add("pale_hanging_moss"); + + config.addDefault("Abilities.Fire.Combustion.Enabled", true); + config.addDefault("Abilities.Fire.Combustion.Description", "Hold Shift to focus large amounts of energy into your body, " + + "Release Shift to fire Combustion. Move your mouse to " + + "direct where the beam travels. Left-Click to detonate " + + "the beam manually"); + config.addDefault("Abilities.Fire.Combustion.Damage", 4.0); + config.addDefault("Abilities.Fire.Combustion.FireTick", 100); + config.addDefault("Abilities.Fire.Combustion.MisfireModifier", -1); + config.addDefault("Abilities.Fire.Combustion.Power", 3); + config.addDefault("Abilities.Fire.Combustion.Range", 100); + config.addDefault("Abilities.Fire.Combustion.Speed", 0.65); + config.addDefault("Abilities.Fire.Combustion.Warmup", 1500); + config.addDefault("Abilities.Fire.Combustion.Cooldown", 5000); + config.addDefault("Abilities.Fire.Combustion.RegenTime", 10000); + config.addDefault("Abilities.Fire.Combustion.EntityCollisionRadius", 1.3); + config.addDefault("Abilities.Fire.Combustion.AbilityCollisionRadius", 1.3); + config.addDefault("Abilities.Fire.Combustion.DamageBlocks", true); + config.addDefault("Abilities.Fire.Combustion.RegenBlocks", true); + config.addDefault("Abilities.Fire.Combustion.WaitForRegen", true); + config.addDefault("Abilities.Fire.Combustion.InstantExplodeIfHit", true); + config.addDefault("Abilities.Fire.Combustion.ExplodeOnDeath", true); + config.addDefault("Abilities.Fire.Combustion.RemovalPolicy.SwappedSlots.Enabled", false); + config.addDefault("Abilities.Fire.Combustion.SkipMaterials", combustionSkipMaterials); + + config.addDefault("Abilities.Fire.Discharge.Enabled", true); + config.addDefault("Abilities.Fire.Discharge.Description", "Left-Click to shoot bolts of electricity out " + + "of your fingertips zapping what ever it hits!"); + config.addDefault("Abilities.Fire.Discharge.Damage", 3.0); + config.addDefault("Abilities.Fire.Discharge.Cooldown", 5000); + config.addDefault("Abilities.Fire.Discharge.AvatarCooldown", 500); + config.addDefault("Abilities.Fire.Discharge.Duration", 1000); + config.addDefault("Abilities.Fire.Discharge.SlotSwapping", false); + config.addDefault("Abilities.Fire.Discharge.EntityCollisionRadius", 1.0); + config.addDefault("Abilities.Fire.Discharge.AbilityCollisionRadius", 1.0); + config.addDefault("Abilities.Fire.Discharge.Sound.Volume", 0.6); + config.addDefault("Abilities.Fire.Discharge.Sound.Interval", 6); + + config.addDefault("Abilities.Fire.FireBall.Enabled", true); + config.addDefault("Abilities.Fire.FireBall.Description", "To use, simply Left-Click to shoot a fireball at your target!"); + config.addDefault("Abilities.Fire.FireBall.Cooldown", 3000); + config.addDefault("Abilities.Fire.FireBall.Range", 50); + config.addDefault("Abilities.Fire.FireBall.Damage", 3.0); + config.addDefault("Abilities.Fire.FireBall.FireDuration", 2000); + config.addDefault("Abilities.Fire.FireBall.Controllable", false); + config.addDefault("Abilities.Fire.FireBall.FireTrail", true); + config.addDefault("Abilities.Fire.FireBall.CollisionRadius", 1.1); + config.addDefault("Abilities.Fire.FireBall.Collisions.FireShield.Enabled", true); + config.addDefault("Abilities.Fire.FireBall.Collisions.FireShield.RemoveFirst", true); + config.addDefault("Abilities.Fire.FireBall.Collisions.FireShield.RemoveSecond", false); + config.addDefault("Abilities.Fire.FireBall.Collisions.AirShield.Enabled", true); + config.addDefault("Abilities.Fire.FireBall.Collisions.AirShield.RemoveFirst", false); + config.addDefault("Abilities.Fire.FireBall.Collisions.AirShield.RemoveSecond", false); + config.addDefault("Abilities.Fire.FireBall.Collisions.AirShield.Reflect", true); + + config.addDefault("Abilities.Fire.FireBreath.Enabled", true); + config.addDefault("Abilities.Fire.FireBreath.Description", "To use, hold Sneak (Default: Shift) to start breathing " + + "fire! Some Firebenders possess the power to infuse color " + + "when they breathe, it's unclear how they do this, but some suggest " + + "it can be obtained by saying \"Bring fire and light together as one and allow the breath of color\" " + + "and can be brought back to normal by saying \"Split the bond of fire " + + "and light and set the color free\"."); + config.addDefault("Abilities.Fire.FireBreath.Cooldown", 5000); + config.addDefault("Abilities.Fire.FireBreath.Duration", 3000); + config.addDefault("Abilities.Fire.FireBreath.Particles", 3); + config.addDefault("Abilities.Fire.FireBreath.Damage.Player", 1.0); + config.addDefault("Abilities.Fire.FireBreath.Damage.Mob", 2.0); + config.addDefault("Abilities.Fire.FireBreath.FireDuration", 3000); + config.addDefault("Abilities.Fire.FireBreath.Range", 10); + config.addDefault("Abilities.Fire.FireBreath.Avatar.FireEnabled", true); + config.addDefault("Abilities.Fire.FireBreath.Melt.Enabled", true); + config.addDefault("Abilities.Fire.FireBreath.Melt.Chance", 3); + config.addDefault("Abilities.Fire.FireBreath.RainbowBreath.Enabled", true); + config.addDefault("Abilities.Fire.FireBreath.RainbowBreath.EnabledMessage", "You have bonded fire with light and can now breathe pure color."); + config.addDefault("Abilities.Fire.FireBreath.RainbowBreath.DisabledMessage", "You have split your bond of color and light."); + config.addDefault("Abilities.Fire.FireBreath.RainbowBreath.NoAccess", "You don't possess the power to bond light with fire."); + + config.addDefault("Abilities.Fire.FireComet.Enabled", true); + config.addDefault("Abilities.Fire.FireComet.Description", "Harnessing the power of Sozin's Comet, a firebender can create a great " + + "ball of fire, with much destructive power. Only useable during Sozin's Comet or while in the AvatarState, hold Sneak (Default: Shift) " + + "to start charging the ability up. Once the ability is charged, a large mass of particles will follow your cursor, until you release sneak, " + + "launching the great ball of fire in the direction you are looking."); + config.addDefault("Abilities.Fire.FireComet.Cooldown", 45000); + config.addDefault("Abilities.Fire.FireComet.ChargeUp", 7000); + config.addDefault("Abilities.Fire.FireComet.Damage", 6.0); + config.addDefault("Abilities.Fire.FireComet.BlastRadius", 3.0); + config.addDefault("Abilities.Fire.FireComet.SozinsComet.Cooldown", 30000); + config.addDefault("Abilities.Fire.FireComet.SozinsComet.ChargeUp", 5000); + config.addDefault("Abilities.Fire.FireComet.SozinsComet.Damage", 12.0); + config.addDefault("Abilities.Fire.FireComet.SozinsComet.BlastRadius", 5.0); + config.addDefault("Abilities.Fire.FireComet.Range", 50); + config.addDefault("Abilities.Fire.FireComet.RegenDelay", 15000); + config.addDefault("Abilities.Fire.FireComet.SozinsCometOnly", true); + config.addDefault("Abilities.Fire.FireComet.AvatarStateBypassComet", true); + + config.addDefault("Abilities.Fire.FirePunch.Enabled", true); + config.addDefault("Abilities.Fire.FirePunch.Description", "This basic ability allows a Firebender to channel their energies into a " + + "single punch, igniting and damaging the victim."); + config.addDefault("Abilities.Fire.FirePunch.Cooldown", 4000); + config.addDefault("Abilities.Fire.FirePunch.FireTicks", 2000); + config.addDefault("Abilities.Fire.FirePunch.Damage", 2.0); + config.addDefault("Abilities.Fire.FirePunch.BurnsDroppedItems", true); + + config.addDefault("Abilities.Fire.FireShots.Enabled", true); + config.addDefault("Abilities.Fire.FireShots.Description", "To use, tap Sneak (Default: Shift) to summon a " + + "FireBalls at your hand, then Left Click to shoot off each ball! " + + "Each shot will follow the cursor until it runs out or hits something! " + + "Tap Sneak again to switch your main hand."); + config.addDefault("Abilities.Fire.FireShots.Cooldown", 3000); + config.addDefault("Abilities.Fire.FireShots.Range", 50); + config.addDefault("Abilities.Fire.FireShots.FireBalls", 4); + config.addDefault("Abilities.Fire.FireShots.FireDuration", 3000); + config.addDefault("Abilities.Fire.FireShots.Damage", 2.0); + config.addDefault("Abilities.Fire.FireShots.CollisionRadius", 0.9); + config.addDefault("Abilities.Fire.FireShots.Collisions.FireShield.Enabled", true); + config.addDefault("Abilities.Fire.FireShots.Collisions.FireShield.RemoveFirst", true); + config.addDefault("Abilities.Fire.FireShots.Collisions.FireShield.RemoveSecond", false); + config.addDefault("Abilities.Fire.FireShots.Collisions.AirShield.Enabled", true); + config.addDefault("Abilities.Fire.FireShots.Collisions.AirShield.RemoveFirst", false); + config.addDefault("Abilities.Fire.FireShots.Collisions.AirShield.RemoveSecond", false); + config.addDefault("Abilities.Fire.FireShots.Collisions.AirShield.Reflect", true); + + config.addDefault("Abilities.Fire.FireSki.Enabled", true); + config.addDefault("Abilities.Fire.FireSki.Cooldown", 6000); + config.addDefault("Abilities.Fire.FireSki.Duration", 6000); + config.addDefault("Abilities.Fire.FireSki.Speed", 0.7); + config.addDefault("Abilities.Fire.FireSki.IgniteEntities", true); + config.addDefault("Abilities.Fire.FireSki.FireTicks", 60); + config.addDefault("Abilities.Fire.FireSki.RequiredHeight", 0.7); + config.addDefault("Abilities.Fire.FireSki.PunchActivated", false); + + config.addDefault("Abilities.Fire.LightningBurst.Enabled", true); + config.addDefault("Abilities.Fire.LightningBurst.Description", "To use the most explosive lightning move available to a firebender, hold " + + "Sneak (Default: Shift) until blue sparks appear in front of you. Upon releasing, " + + "you will unleash an electrical sphere, shocking anyone who gets too close"); + config.addDefault("Abilities.Fire.LightningBurst.Cooldown", 25000); + config.addDefault("Abilities.Fire.LightningBurst.ChargeUp", 4000); + config.addDefault("Abilities.Fire.LightningBurst.AvatarCooldown", 1000); + config.addDefault("Abilities.Fire.LightningBurst.AvatarChargeUp", 1000); + config.addDefault("Abilities.Fire.LightningBurst.Radius", 12); + config.addDefault("Abilities.Fire.LightningBurst.Damage", 9.0); + config.addDefault("Abilities.Fire.LightningBurst.Sound.Volume", 0.6); + config.addDefault("Abilities.Fire.LightningBurst.Sound.Interval", 6); + + config.addDefault("Abilities.Water.Bloodbending.Enabled", true); + config.addDefault("Abilities.Water.Bloodbending.Description", "This ability allows a skilled waterbender " + + "to bend the water within an enemy's blood, granting them full " + + "control over the enemy's limbs. This ability is extremely dangerous " + + "and is to be used carefully. To use, sneak while looking at an entity " + + "and its body will follow your movement. If you click, you will launch " + + "the entity towards whatever you were looking at when you clicked. The " + + "entity may collide with others, injuring them and the other one further."); + config.addDefault("Abilities.Water.Bloodbending.NightOnly", false); + config.addDefault("Abilities.Water.Bloodbending.FullMoonOnly", false); + config.addDefault("Abilities.Water.Bloodbending.UndeadMobs", true); + config.addDefault("Abilities.Water.Bloodbending.IgnoreWalls", false); + config.addDefault("Abilities.Water.Bloodbending.RequireBound", false); + config.addDefault("Abilities.Water.Bloodbending.Distance", 6); + config.addDefault("Abilities.Water.Bloodbending.HoldTime", 10000); + config.addDefault("Abilities.Water.Bloodbending.Cooldown", 4000); + + config.addDefault("Abilities.Water.BloodPuppet.Enabled", true); + config.addDefault("Abilities.Water.BloodPuppet.Description", "This very high-level bloodbending ability lets " + + "a master control entities' limbs, forcing them to " + + "attack the master's target. To use this ability, you must " + + "be a bloodbender. Next, sneak while targeting " + + "a mob or player and you will start controlling them. To " + + "make the entity hit another, click. To release your " + + "target, stop sneaking. This ability has NO cooldown, but " + + "may only be usable during the night depending on the " + + "server configuration."); + config.addDefault("Abilities.Water.BloodPuppet.NightOnly", false); + config.addDefault("Abilities.Water.BloodPuppet.FullMoonOnly", false); + config.addDefault("Abilities.Water.BloodPuppet.UndeadMobs", true); + config.addDefault("Abilities.Water.BloodPuppet.IgnoreWalls", false); + config.addDefault("Abilities.Water.BloodPuppet.RequireBound", false); + config.addDefault("Abilities.Water.BloodPuppet.Distance", 6); + config.addDefault("Abilities.Water.BloodPuppet.HoldTime", 10000); + config.addDefault("Abilities.Water.BloodPuppet.Cooldown", 4000); + + config.addDefault("Abilities.Water.Drain.Enabled", true); + config.addDefault("Abilities.Water.Drain.Description", "Inspired by how Hama drained water from the fire lilies, many benders " + + "have practiced in the skill of draining water from plants! With this ability bound, " + + "Sneak (Default: Shift) near/around plant sources to drain the water out of them to fill up any " + + "bottles/buckets in your inventory! Alternatively, if you have nothing to fill" + + " and blasts are enabled in the config, you will be able to create mini blasts " + + "of water to shoot at your targets! Aleternatively, this ability can also be used to quickly fill up " + + "bottles from straight water sources or from falling rain!"); + config.addDefault("Abilities.Water.Drain.RegenDelay", 15000); + config.addDefault("Abilities.Water.Drain.Duration", 2000); + config.addDefault("Abilities.Water.Drain.Cooldown", 2000); + config.addDefault("Abilities.Water.Drain.AbsorbSpeed", 0.1); + config.addDefault("Abilities.Water.Drain.AbsorbChance", 20); + config.addDefault("Abilities.Water.Drain.AbsorbRate", 6); + config.addDefault("Abilities.Water.Drain.Radius", 6); + config.addDefault("Abilities.Water.Drain.HoldRange", 2); + config.addDefault("Abilities.Water.Drain.AllowRainSource", true); + config.addDefault("Abilities.Water.Drain.BlastsEnabled", true); + config.addDefault("Abilities.Water.Drain.KeepSource", false); + config.addDefault("Abilities.Water.Drain.BlastSpeed", 1); + config.addDefault("Abilities.Water.Drain.BlastDamage", 1.5); + config.addDefault("Abilities.Water.Drain.BlastRange", 20); + config.addDefault("Abilities.Water.Drain.MaxBlasts", 4); + config.addDefault("Abilities.Water.Drain.DrainTempBlocks", true); + + config.addDefault("Abilities.Water.FrostBreath.Enabled", true); + config.addDefault("Abilities.Water.FrostBreath.Description", "As demonstrated by Katara, a Waterbender is able to freeze their breath, " + + "causing anything it touches to be frozen! With this ability bound, simply hold " + + "Sneak (Default: Shift) to start breathing frost!"); + config.addDefault("Abilities.Water.FrostBreath.Cooldown", 15000); + config.addDefault("Abilities.Water.FrostBreath.Duration", 3000); + config.addDefault("Abilities.Water.FrostBreath.Particles", 3); + config.addDefault("Abilities.Water.FrostBreath.FrostDuration", 5000); + config.addDefault("Abilities.Water.FrostBreath.FrozenWaterDuration", 10000); + config.addDefault("Abilities.Water.FrostBreath.Range", 10); + config.addDefault("Abilities.Water.FrostBreath.Snow", true); + config.addDefault("Abilities.Water.FrostBreath.SnowDuration", 5000); + config.addDefault("Abilities.Water.FrostBreath.BendableSnow", false); + config.addDefault("Abilities.Water.FrostBreath.Damage.Enabled", false); + config.addDefault("Abilities.Water.FrostBreath.Damage.Player", 1.0); + config.addDefault("Abilities.Water.FrostBreath.Damage.Mob", 2.0); + config.addDefault("Abilities.Water.FrostBreath.Slow.Enabled", true); + config.addDefault("Abilities.Water.FrostBreath.Slow.Duration", 4000); + config.addDefault("Abilities.Water.FrostBreath.RestrictBiomes", true); + + config.addDefault("Abilities.Water.HealingWaters.Enabled", true); + config.addDefault("Abilities.Water.HealingWaters.Description", "To use this ability, the bender has to be partially submerged " + + "in water, OR be holding either a bottle of water or a water bucket." + + " This move will heal the player automatically if they have it equipped " + + "and are standing in water. If the player sneaks while in water and is targeting" + + " another entity, the bender will heal the targeted entity. The alternate " + + "healing method requires the bender to be holding a bottle of water or a water" + + " bucket. To start healing simply sneak, however if the bender is targeting " + + "a mob while sneaking, the bender will heal the targeted mob."); + config.addDefault("Abilities.Water.HealingWaters.Power", 1); + config.addDefault("Abilities.Water.HealingWaters.Range", 5); + config.addDefault("Abilities.Water.HealingWaters.DrainChance", 5); + config.addDefault("Abilities.Water.HealingWaters.DynamicLight.Enabled", true); + config.addDefault("Abilities.Water.HealingWaters.DynamicLight.Brightness", 10); + config.addDefault("Abilities.Water.HealingWaters.DynamicLight.KeepAlive", 1500); + + config.addDefault("Abilities.Water.IceClaws.Enabled", true); + config.addDefault("Abilities.Water.IceClaws.Description", "As demonstrated by Hama, a Waterbender can pull water out of thin air to create claws " + + "at the tips of their fingers. With IceClaws bound, hold Sneak (Default: Shift) to " + + "start pulling water out the air until you form claws at your finger " + + "tips, then attack an enemy to slow them down and do a bit of damage!"); + config.addDefault("Abilities.Water.IceClaws.Cooldown", 6000); + config.addDefault("Abilities.Water.IceClaws.ChargeTime", 1000); + config.addDefault("Abilities.Water.IceClaws.Range", 10); + config.addDefault("Abilities.Water.IceClaws.Throwable", true); + config.addDefault("Abilities.Water.IceClaws.Punch.Cooldown", 4000); + config.addDefault("Abilities.Water.IceClaws.Punch.Damage", 2.0); + config.addDefault("Abilities.Water.IceClaws.Punch.Slowness", 3); + config.addDefault("Abilities.Water.IceClaws.Punch.SlowDuration", 5000); + config.addDefault("Abilities.Water.IceClaws.Throw.Cooldown", 4000); + config.addDefault("Abilities.Water.IceClaws.Throw.Damage", 2.0); + config.addDefault("Abilities.Water.IceClaws.Throw.Slowness", 3); + config.addDefault("Abilities.Water.IceClaws.Throw.SlowDuration", 5000); + config.addDefault("Abilities.Water.IceClaws.Throw.Speed", 1.0); + config.addDefault("Abilities.Water.IceClaws.AllowHandSwap", true); + + config.addDefault("Abilities.Water.IceWall.Enabled", true); + config.addDefault("Abilities.Water.IceWall.Description", "IceWall allows an icebender to create a wall of ice, similar to " + + "raiseearth. To use, simply sneak while targeting either water, ice, or snow. " + + "To break the wall, you must sneak again while targeting it. Be aware that " + + "other icebenders can break your own shields, and if you are too close you " + + "can get hurt by the shards."); + config.addDefault("Abilities.Water.IceWall.Cooldown", 4000); + config.addDefault("Abilities.Water.IceWall.Width", 6); + config.addDefault("Abilities.Water.IceWall.MaxHeight", 5); + config.addDefault("Abilities.Water.IceWall.MinHeight", 3); + config.addDefault("Abilities.Water.IceWall.MaxWallHealth", 12); + config.addDefault("Abilities.Water.IceWall.MinWallHealth", 8); + config.addDefault("Abilities.Water.IceWall.Range", 8); + config.addDefault("Abilities.Water.IceWall.Damage", 4.0); + config.addDefault("Abilities.Water.IceWall.CanBreak", true); + config.addDefault("Abilities.Water.IceWall.Stackable", false); + config.addDefault("Abilities.Water.IceWall.LifeTime.Enabled", false); + config.addDefault("Abilities.Water.IceWall.LifeTime.Duration", 10000); + config.addDefault("Abilities.Water.IceWall.WallDamage", true); + config.addDefault("Abilities.Water.IceWall.WallDamage.Torrent", 5); + config.addDefault("Abilities.Water.IceWall.WallDamage.TorrentFreeze", 9); + config.addDefault("Abilities.Water.IceWall.WallDamage.IceBlast", 8); + config.addDefault("Abilities.Water.IceWall.WallDamage.Fireblast", 3); + config.addDefault("Abilities.Water.IceWall.WallDamage.FireblastCharged", 5); + config.addDefault("Abilities.Water.IceWall.WallDamage.Lightning", 12); + config.addDefault("Abilities.Water.IceWall.WallDamage.Combustion", 12); + config.addDefault("Abilities.Water.IceWall.WallDamage.EarthSmash", 8); + config.addDefault("Abilities.Water.IceWall.WallDamage.AirBlast", 2); + + config.addDefault("Abilities.Water.WakeFishing.Enabled", true); + config.addDefault("Abilities.Water.WakeFishing.Description", "With this ability bound, hold Sneak (Default: Shift) at a water block and " + + "don't lose focus of that block. Eventually some fish will investigate " + + "the wake and swim out at you!"); + config.addDefault("Abilities.Water.WakeFishing.Cooldown", 10000); + config.addDefault("Abilities.Water.WakeFishing.Duration", 20000); + config.addDefault("Abilities.Water.WakeFishing.Range", 5); + + config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Enabled", true); + config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Description", "Create a swirling mass of water that drags any entity that enters it to the bottom " + + "of the whirlpool."); + config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Cooldown", 25000); + config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Duration", 15000); + config.addDefault("Abilities.Water.WaterCombo.Maelstrom.MaxDepth", 5); + config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Range", 10); + config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Combination", Arrays.asList("PhaseChange:SHIFT_DOWN", "Torrent:LEFT_CLICK", "Torrent:LEFT_CLICK")); + config.addDefault("Abilities.Water.WaterCombo.Maelstrom.Instructions", "PhaseChange (Hold sneak) > Torrent (Left-click) > Torrent (Left-click)"); + + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Enabled", true); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Description", "Some Waterbenders have managed to create torrents of water much stronger than a regular torrent, " + + "that can carry them selves and others, as well as being able to freeze the entire stream whenever. The bender must stay focused on the flow or else the flow will stop." + + " If you Sneak (Default: Shift) while controlling the stream, the stream will return to you."); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Cooldown", 8000); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Duration", 8000); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.MeltDelay", 5000); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.SourceRange", 10); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.MaxRange", 40); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.MinRange", 8); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Trail", 80); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.BottleSource", false); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.PlantSource", false); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.RemoveOnAnyDamage", false); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Size.Normal", 1); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Size.AvatarState", 3); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Size.FullmoonSmall", 2); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Size.FullmoonLarge", 3); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.IsAvatarStateToggle", true); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.AvatarStateDuration", 60000); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.PlayerStayNearSource", true); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.MaxDistanceFromSource", 100); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.FullMoon.Enabled", true); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.FullMoon.Modifier.Cooldown", 3); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.FullMoon.Modifier.Duration", 2); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.PlayerRideOwnFlow", true); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Combination", Arrays.asList("WaterManipulation:SHIFT_DOWN", "WaterManipulation:SHIFT_UP", "Torrent:SHIFT_DOWN", "Torrent:SHIFT_UP", "Torrent:SHIFT_DOWN", "WaterManipulation:SHIFT_UP")); + config.addDefault("Abilities.Water.WaterCombo.WaterFlow.Instructions", "WaterManipulation (Tap sneak) > Torrent (Tap sneak) > Torrent (Hold sneak) > WaterManipulation (Release sneak)"); + + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Enabled", true); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Description", "Skilled Waterbenders are able to create two spinning rings of water around their bodies, " + + "which can be used as a defensive ability or for an offensive attack."); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Cooldown", 7000); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Damage", 3.0); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.RingSize", 3.5); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Range", 40); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.SourceRange", 10); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Speed", 2); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.AnimationSpeed", 3); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.PlantSource", true); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.SnowSource", true); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.RequireAdjacentPlants", true); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.BottleSource", false); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.AbilityCollisionRadius", 1.6); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.EntityCollisionRadius", 1.6); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Collisions.FireShield.Enabled", false); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Collisions.FireShield.RemoveFirst", true); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Collisions.FireShield.RemoveSecond", false); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Combination", Arrays.asList("Torrent:SHIFT_DOWN", "Torrent:SHIFT_UP", "Torrent:SHIFT_DOWN", "Torrent:SHIFT_UP", "WaterManipulation:SHIFT_DOWN")); + config.addDefault("Abilities.Water.WaterCombo.WaterGimbal.Instructions", "Torrent (Tap sneak) > Torrent (Tap sneak) > WaterManipulation (Hold sneak) > WaterManipulation (Left-click multiple times)"); + + config.addDefault("Abilities.Water.Ice.Passive.Skate.Enabled", true); + config.addDefault("Abilities.Water.Ice.Passive.Skate.SpeedFactor", 4); + + config.addDefault("Abilities.Chi.Backstab.Enabled", true); + config.addDefault("Abilities.Chi.Backstab.Description", "Strike your foe in the back with a hard jab, temporariliy blocking their Chi, and " + + "inflicting a lot of damage! This ability has a long cooldown. You must hit the target in the back or this ability won't work!"); + config.addDefault("Abilities.Chi.Backstab.Cooldown", 8500); + config.addDefault("Abilities.Chi.Backstab.Damage", 6.0); + config.addDefault("Abilities.Chi.Backstab.MaxActivationAngle", 90); + + config.addDefault("Abilities.Chi.DaggerThrow.Enabled", true); + config.addDefault("Abilities.Chi.DaggerThrow.Description", "With this ability bound, Left-Click in " + + "rapid succession to shoot arrows out of your inventory at your target!"); + config.addDefault("Abilities.Chi.DaggerThrow.Cooldown", 3000); + config.addDefault("Abilities.Chi.DaggerThrow.MaxDaggers.Enabled", true); + config.addDefault("Abilities.Chi.DaggerThrow.MaxDaggers.Amount", 6); + config.addDefault("Abilities.Chi.DaggerThrow.Damage", 1.0); + config.addDefault("Abilities.Chi.DaggerThrow.ParticleTrail", true); + config.addDefault("Abilities.Chi.DaggerThrow.RequireArrows", false); + config.addDefault("Abilities.Chi.DaggerThrow.AllowPickup", false); + config.addDefault("Abilities.Chi.DaggerThrow.AbilityCollisionRadius", 0.5); + config.addDefault("Abilities.Chi.DaggerThrow.Interactions.WaterSpout.Enabled", true); + config.addDefault("Abilities.Chi.DaggerThrow.Interactions.WaterSpout.Cooldown", 1000); + config.addDefault("Abilities.Chi.DaggerThrow.Interactions.WaterSpout.HitsRequired", 1); + config.addDefault("Abilities.Chi.DaggerThrow.Interactions.AirSpout.Enabled", true); + config.addDefault("Abilities.Chi.DaggerThrow.Interactions.AirSpout.Cooldown", 1000); + config.addDefault("Abilities.Chi.DaggerThrow.Interactions.AirSpout.HitsRequired", 1); + + String[] invalidWallRun = {Material.BARRIER.name()}; + config.addDefault("Abilities.Passives.WallRun.Enabled", true); + config.addDefault("Abilities.Passives.WallRun.Cooldown", 6000); + config.addDefault("Abilities.Passives.WallRun.Duration", 20000); + config.addDefault("Abilities.Passives.WallRun.Particles", true); + config.addDefault("Abilities.Passives.WallRun.Air", true); + config.addDefault("Abilities.Passives.WallRun.Earth", false); + config.addDefault("Abilities.Passives.WallRun.Water", false); + config.addDefault("Abilities.Passives.WallRun.Fire", true); + config.addDefault("Abilities.Passives.WallRun.Chi", true); + config.addDefault("Abilities.Passives.WallRun.InvalidBlocks", invalidWallRun); + + config.options().copyDefaults(true); + plugin.saveConfig(); + } + + private void addDeathMessages() { + FileConfiguration lang = ConfigManager.languageConfig.get(); + + //Fire + lang.addDefault("Abilities.Fire.FireComet.DeathMessage", "{victim} was squashed under the pressure of {attacker}'s {ability}"); + lang.addDefault("Abilities.Fire.FireBall.DeathMessage", "{victim} burst from {attacker}'s {ability}"); + lang.addDefault("Abilities.Fire.FireBreath.DeathMessage", "{victim} was consumed {attacker}'s {ability}"); + lang.addDefault("Abilities.Fire.Discharge.DeathMessage", "{victim} couldn't take {attacker}'s {ability}"); + lang.addDefault("Abilities.Fire.FirePunch.DeathMessage", "{victim} punched out from {attacker}'s {ability}"); + lang.addDefault("Abilities.Fire.FireShots.DeathMessage", "{victim} was shot by {attacker}'s {ability}"); + lang.addDefault("Abilities.Fire.LightningBurst.DeathMessage", "{victim} crackled out of existence from {attacker}'s {ability}"); + + //Water + lang.addDefault("Abilities.Water.Drain.DeathMessage", "{victim} was blasted by {attacker}'s {ability}"); + lang.addDefault("Abilities.Water.FrostBreath.DeathMessage", "{victim} shattered from {attacker}'s {ability}"); + lang.addDefault("Abilities.Water.IceClaws.DeathMessage", "{victim} was ripped to shreds by {attacker}'s {ability}"); + lang.addDefault("Abilities.Water.IceWall.DeathMessage", "{victim} was collateral to {attacker}'s exploding {ability}"); + lang.addDefault("Abilities.Water.WaterBlast.DeathMessage", "{victim} was blasted by {attacker}'s {ability}"); + lang.addDefault("Abilities.Water.Combo.WaterGimbal.DeathMessage", "{victim} was ripped apart by {attacker}'s {ability}"); + + //Earth + lang.addDefault("Abilities.Earth.EarthKick.DeathMessage", "{victim} got too much dirt in their eye from {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.EarthLine.DeathMessage", "{victim} lost their footing from {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.EarthShard.DeathMessage", "{victim} got blasted apart {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.LavaDisc.DeathMessage", "{victim} sliced in half by {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.LavaFlux.DeathMessage", "{victim} couldn't take the heat from {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.LavaThrow.DeathMessage", "{victim} melted from {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.MetalFragments.DeathMessage", "{victim} was shredded apart from {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.MetalShred.DeathMessage", "{victim} was in the way of {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.MudSurge.DeathMessage", "{victim} drowned in mud from {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.SandBlast.DeathMessage", "{victim} was sandblasted to oblivion from {attacker}'s {ability}"); + lang.addDefault("Abilities.Earth.Combo.MagmaBlast.DeathMessage", "{victim} was obliterated by {attacker}'s {ability}"); + + //Air + lang.addDefault("Abilities.Air.AirBlade.DeathMessage", "{victim} was sliced in two by {attacker}'s {ability}"); + lang.addDefault("Abilities.Air.AirPunch.DeathMessage", "{victim} was exploded by {attacker}'s {ability}"); + lang.addDefault("Abilities.Air.SonicBlast.DeathMessage", "{victim}'s ears burst after {attacker}'s {ability}"); + + //Chi + lang.addDefault("Abilities.Chi.DaggerThrow.DeathMessage", "{victim} got stabbed too many times from {attacker}'s {ability}"); + lang.addDefault("Abilities.Chi.Backstab.DeathMessage", "{victim} fell victim to {attacker}'s {ability}"); + + //Avatar + lang.addDefault("Abilities.Avatar.SpiritBeam.DeathMessage", "{victim} was erased from existence by {attacker}'s {ability}"); + lang.addDefault("Abilities.Avatar.ElementSphereAir.DeathMessage", "{victim} was blasted apart by {attacker}'s \u00A75ElementSphere"); + lang.addDefault("Abilities.Avatar.ElementSphereFire.DeathMessage", "{victim} was burnt to cinders by {attacker}'s \u00A75ElementSphere"); + lang.addDefault("Abilities.Avatar.ElementSphereEarth.DeathMessage", "{victim} was crushed by {attacker}'s \u00A75ElementSphere"); + lang.addDefault("Abilities.Avatar.ElementSphereWater.DeathMessage", "{victim} was sliced apart by {attacker}'s \u00A75ElementSphere"); + lang.addDefault("Abilities.Avatar.ElementSphereStream.DeathMessage", "{victim} took the full force of {attacker}'s \u00A75ElementSphere"); + + ConfigManager.languageConfig.save(); + } + + private void setupElementSphereNames() { + FileConfiguration lang = ConfigManager.languageConfig.get(); + + lang.addDefault("Abilities.Avatar.ElementSphereAir.Name", "Air"); + lang.addDefault("Abilities.Avatar.ElementSphereFire.Name", "Fire"); + lang.addDefault("Abilities.Avatar.ElementSphereEarth.Name", "Earth"); + lang.addDefault("Abilities.Avatar.ElementSphereWater.Name", "Water"); + lang.addDefault("Abilities.Avatar.ElementSphereStream.Name", "Stream"); + + ConfigManager.languageConfig.save(); + } + + public static ConfigurationSection getConfig(Player player) { + if (player == null) + return getConfig((World)null); + return getConfig(player.getWorld()); + } + + public static ConfigurationSection getConfig(World world) { + boolean perWorldConfig = plugin.getConfig().getBoolean("Properties.PerWorldConfig"); + + if (world == null || !perWorldConfig) { + return plugin.getConfig(); + } + + String prefix = "Worlds." + world.getName(); + return new SubsectionConfigurationDecorator(plugin.getConfig(), prefix); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/event/PKCommandEvent.java b/src/com/jedk1/jedcore/event/PKCommandEvent.java index 76af79e..3886951 100644 --- a/src/com/jedk1/jedcore/event/PKCommandEvent.java +++ b/src/com/jedk1/jedcore/event/PKCommandEvent.java @@ -24,8 +24,7 @@ public enum CommandType { TOGGLE, VERSION, WHO, - JEDCORE, - SCOREBOARD; + JEDCORE; public static CommandType getType(String string) { for (CommandType element : CommandType.values()) { diff --git a/src/com/jedk1/jedcore/listener/AbilityListener.java b/src/com/jedk1/jedcore/listener/AbilityListener.java index 2f04468..1e0f109 100644 --- a/src/com/jedk1/jedcore/listener/AbilityListener.java +++ b/src/com/jedk1/jedcore/listener/AbilityListener.java @@ -1,79 +1,43 @@ package com.jedk1.jedcore.listener; import com.jedk1.jedcore.JedCore; -import com.jedk1.jedcore.ability.airbending.AirBlade; -import com.jedk1.jedcore.ability.airbending.AirBreath; -import com.jedk1.jedcore.ability.airbending.AirGlide; -import com.jedk1.jedcore.ability.airbending.AirPunch; -import com.jedk1.jedcore.ability.airbending.Meditate; -import com.jedk1.jedcore.ability.airbending.SonicBlast; +import com.jedk1.jedcore.ability.airbending.*; import com.jedk1.jedcore.ability.avatar.SpiritBeam; import com.jedk1.jedcore.ability.avatar.elementsphere.ElementSphere; import com.jedk1.jedcore.ability.chiblocking.DaggerThrow; -import com.jedk1.jedcore.ability.earthbending.EarthKick; -import com.jedk1.jedcore.ability.earthbending.EarthLine; -import com.jedk1.jedcore.ability.earthbending.EarthPillar; -import com.jedk1.jedcore.ability.earthbending.EarthShard; -import com.jedk1.jedcore.ability.earthbending.EarthSurf; -import com.jedk1.jedcore.ability.earthbending.Fissure; -import com.jedk1.jedcore.ability.earthbending.LavaDisc; -import com.jedk1.jedcore.ability.earthbending.LavaFlux; -import com.jedk1.jedcore.ability.earthbending.LavaThrow; -import com.jedk1.jedcore.ability.earthbending.MagnetShield; -import com.jedk1.jedcore.ability.earthbending.MetalArmor; -import com.jedk1.jedcore.ability.earthbending.MetalFragments; -import com.jedk1.jedcore.ability.earthbending.MetalHook; -import com.jedk1.jedcore.ability.earthbending.MetalShred; -import com.jedk1.jedcore.ability.earthbending.MudSurge; -import com.jedk1.jedcore.ability.earthbending.SandBlast; +import com.jedk1.jedcore.ability.earthbending.*; import com.jedk1.jedcore.ability.earthbending.combo.Crevice; import com.jedk1.jedcore.ability.earthbending.combo.MagmaBlast; -import com.jedk1.jedcore.ability.firebending.Combustion; -import com.jedk1.jedcore.ability.firebending.Discharge; -import com.jedk1.jedcore.ability.firebending.FireBall; -import com.jedk1.jedcore.ability.firebending.FireBreath; -import com.jedk1.jedcore.ability.firebending.FireComet; -import com.jedk1.jedcore.ability.firebending.FirePunch; -import com.jedk1.jedcore.ability.firebending.FireShots; -import com.jedk1.jedcore.ability.firebending.FireSki; -import com.jedk1.jedcore.ability.firebending.LightningBurst; +import com.jedk1.jedcore.ability.firebending.*; import com.jedk1.jedcore.ability.passive.WallRun; -import com.jedk1.jedcore.ability.waterbending.BloodPuppet; -import com.jedk1.jedcore.ability.waterbending.Drain; -import com.jedk1.jedcore.ability.waterbending.FrostBreath; -import com.jedk1.jedcore.ability.waterbending.IceClaws; -import com.jedk1.jedcore.ability.waterbending.IceWall; -import com.jedk1.jedcore.ability.waterbending.WakeFishing; +import com.jedk1.jedcore.ability.waterbending.*; import com.jedk1.jedcore.ability.waterbending.combo.WaterFlow; import com.jedk1.jedcore.ability.waterbending.combo.WaterGimbal; +import com.jedk1.jedcore.util.ThreadUtil; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ProjectKorra; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.AvatarAbility; -import com.projectkorra.projectkorra.ability.ChiAbility; -import com.projectkorra.projectkorra.ability.CoreAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; -import com.projectkorra.projectkorra.ability.FireAbility; -import com.projectkorra.projectkorra.ability.WaterAbility; +import com.projectkorra.projectkorra.ability.*; import com.projectkorra.projectkorra.ability.util.MultiAbilityManager; import com.projectkorra.projectkorra.airbending.Suffocate; import com.projectkorra.projectkorra.earthbending.EarthArmor; import com.projectkorra.projectkorra.earthbending.lava.LavaFlow; import com.projectkorra.projectkorra.firebending.FireJet; import com.projectkorra.projectkorra.util.MovementHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.waterbending.blood.Bloodbending; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.entity.Arrow; import org.bukkit.entity.EntityType; +import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityChangeBlockEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; @@ -90,455 +54,492 @@ public class AbilityListener implements Listener { - JedCore plugin; - - public AbilityListener(JedCore plugin) { - this.plugin = plugin; - } - - private final List recentlyDropped = new ArrayList<>(); - - @EventHandler(priority = EventPriority.LOWEST) - // Abilities that should bypass punch cancels should be handled here. - public void onPlayerSwingBypassCancel(PlayerInteractEvent event) { - Player player = event.getPlayer(); - if (event.getHand() != EquipmentSlot.HAND) { - return; - } - if (event.getAction() != Action.LEFT_CLICK_BLOCK && event.getAction() != Action.LEFT_CLICK_AIR) { - return; - } - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - if (bPlayer == null) { - return; - } - - if (Suffocate.isBreathbent(player) || bPlayer.isChiBlocked()) { - return; - } - - if (Bloodbending.isBloodbent(player) || MovementHandler.isStopped(player)) { - return; - } - - CoreAbility coreAbil = bPlayer.getBoundAbility(); - if (coreAbil == null) { - return; - } - - if (!bPlayer.canBendIgnoreCooldowns(coreAbil)) { - return; - } - - if (coreAbil instanceof FireAbility && bPlayer.isElementToggled(Element.FIRE)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Fire.CanBendWithWeapons")) { - return; - } - - // FireSki bypasses punch cancel because the normal version is activated from sneaking alone. - // The punch activation exists just so people don't accidentally activate it, so they should have the same - // requirements for activation. - if (coreAbil instanceof FireJet && FireSki.isPunchActivated(player.getWorld())) { - if (player.isSneaking()) { - FireSki ski = new FireSki(player); - if (ski.isStarted() && !bPlayer.isOnCooldown("FireJet")) { - // The event only needs to be cancelled when FireSki is set to have no cooldown. - // This is to prevent FireJet from activating from the same swing event. - event.setCancelled(true); - } - } - } - } - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerDropItemEvent(PlayerDropItemEvent event) { - recentlyDropped.add(event.getPlayer().getUniqueId()); - Bukkit.getScheduler().runTaskLater(ProjectKorra.plugin, () -> recentlyDropped.remove(event.getPlayer().getUniqueId()), 2L); - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerInventoryInteract(InventoryClickEvent event) { - InventoryAction action = event.getAction(); - if (action == InventoryAction.DROP_ALL_CURSOR || - action == InventoryAction.DROP_ALL_SLOT || - action == InventoryAction.DROP_ONE_CURSOR || - action == InventoryAction.DROP_ONE_SLOT || - action == InventoryAction.UNKNOWN) { - - recentlyDropped.add(event.getWhoClicked().getUniqueId()); - - Bukkit.getScheduler().runTaskLater(ProjectKorra.plugin, () -> { - recentlyDropped.remove(event.getWhoClicked().getUniqueId()); - }, 2L); - } - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerSwing(PlayerInteractEvent event) { - Player player = event.getPlayer(); - - if (recentlyDropped.contains(player.getUniqueId())) return; - - if (event.getHand() != EquipmentSlot.HAND) { - return; - } - if (event.getAction() != Action.LEFT_CLICK_BLOCK && event.getAction() != Action.LEFT_CLICK_AIR) { - return; - } - if (event.getAction() == Action.LEFT_CLICK_BLOCK && event.isCancelled()){ - return; - } - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - if (bPlayer == null) { - return; - } - - if (Suffocate.isBreathbent(player)) { - event.setCancelled(true); - return; - } else if (Bloodbending.isBloodbent(player) || MovementHandler.isStopped(player)) { - event.setCancelled(true); - return; - } else if (bPlayer.isChiBlocked()) { - event.setCancelled(true); - return; - } else if (GeneralMethods.isInteractable(player.getTargetBlock((Set)null, 5))) { - return; - } - - if (bPlayer.isToggled()) { - new WallRun(player); - } - - CoreAbility coreAbil = bPlayer.getBoundAbility(); - if (coreAbil == null) { - if (MultiAbilityManager.hasMultiAbilityBound(player)){ - String abil = MultiAbilityManager.getBoundMultiAbility(player); - if (abil.equalsIgnoreCase("elementsphere")) { - new ElementSphere(player); - } - } - return; - } - - String abilName = bPlayer.getBoundAbilityName(); - Class abilClass = coreAbil.getClass(); - - if (bPlayer.canBendIgnoreCooldowns(coreAbil)) { - - if (coreAbil instanceof AirAbility && bPlayer.isElementToggled(Element.AIR)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Air.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(AirBlade.class)) { - new AirBlade(player); - } - if (abilClass.equals(AirPunch.class)) { - new AirPunch(player); - } - } - - if (coreAbil instanceof EarthAbility && bPlayer.isElementToggled(Element.EARTH)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Earth.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(EarthArmor.class)) { - new MetalArmor(player); - } - if (abilClass.equals(EarthLine.class)) { - EarthLine.shootLine(player); - } - if (abilClass.equals(EarthShard.class)) { - EarthShard.throwShard(player); - } - if (abilClass.equals(EarthSurf.class)) { - new EarthSurf(player); - } - if (abilClass.equals(Fissure.class)) { - new Fissure(player); - } - if (abilClass.equals(LavaFlux.class)) { - new LavaFlux(player); - } - if (abilClass.equals(LavaThrow.class)) { - new LavaThrow(player); - } - if (abilClass.equals(MetalFragments.class)) { - MetalFragments.shootFragment(player); - } - if (abilClass.equals(MetalHook.class)) { - new MetalHook(player); - } - if (abilClass.equals(MetalShred.class)) { - MetalShred.extend(player); - } - if (abilClass.equals(MudSurge.class)) { - MudSurge.mudSurge(player); - } - if (abilClass.equals(SandBlast.class)) { - SandBlast.blastSand(player); - } - if (abilClass.equals(LavaFlow.class)) { - MagmaBlast.performAction(player); - } - if (abilClass.equals(MagnetShield.class)) { - new MagnetShield(player, true); - } - } - - if (coreAbil instanceof FireAbility && bPlayer.isElementToggled(Element.FIRE)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Fire.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(Combustion.class)) { - Combustion.combust(player); - } - if (abilClass.equals(Discharge.class)) { - new Discharge(player); - } - if (abilClass.equals(FireBall.class)) { - new FireBall(player); - } - if (abilClass.equals(FirePunch.class)) { - new FirePunch(player); - } - if (abilClass.equals(FireShots.class)) { - FireShots.fireShot(player); - } - } - - if (coreAbil instanceof WaterAbility && bPlayer.isElementToggled(Element.WATER)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.WATER.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(com.jedk1.jedcore.ability.waterbending.Bloodbending.class)) { - com.jedk1.jedcore.ability.waterbending.Bloodbending.launch(player); - } - if (abilClass.equals(BloodPuppet.class)) { - BloodPuppet.attack(player); - } - if (abilClass.equals(IceClaws.class)) { - IceClaws.throwClaws(player); - } - if (abilName.equals("Drain")) { - Drain.fireBlast(player); - } - if (coreAbil.getName().equalsIgnoreCase("watermanipulation")) { - WaterGimbal.prepareBlast(player); - } - if (coreAbil.getName().equalsIgnoreCase("watermanipulation")) { - WaterFlow.freeze(player); - } - } - if (coreAbil instanceof ChiAbility && bPlayer.isElementToggled(Element.CHI)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Chi.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(DaggerThrow.class)) { - new DaggerThrow(player); - } - } - - if (coreAbil instanceof AvatarAbility) { - if (abilClass.equals(ElementSphere.class)) { - new ElementSphere(player); - } - } - } - } - - public static ConcurrentHashMap recent = new ConcurrentHashMap(); - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerSneak(PlayerToggleSneakEvent event) { - Player player = event.getPlayer(); - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - - if (event.isCancelled() || bPlayer == null) { - return; - } - - String abilName = bPlayer.getBoundAbilityName(); - if (Suffocate.isBreathbent(player)) { - if (!abilName.equalsIgnoreCase("AirSwipe") - && !abilName.equalsIgnoreCase("FireBlast") - && !abilName.equalsIgnoreCase("EarthBlast") - && !abilName.equalsIgnoreCase("WaterManipulation")) { - if(!player.isSneaking()) { - event.setCancelled(true); - } - } - } - - if (MovementHandler.isStopped(player) || Bloodbending.isBloodbent(player)) { - event.setCancelled(true); - return; - } - - CoreAbility coreAbil = bPlayer.getBoundAbility(); - if (coreAbil == null) { - return; - } - - Class abilClass = coreAbil.getClass(); - - if (bPlayer.isChiBlocked()) { - event.setCancelled(true); - return; - } - - if (player.isSneaking() && bPlayer.canBendIgnoreCooldowns(coreAbil)) { - if (coreAbil instanceof FireAbility && bPlayer.isElementToggled(Element.FIRE)) { - if (abilClass.equals(FireShots.class)) { - FireShots.swapHands(player); - } - } - } - - if (!player.isSneaking() && bPlayer.canBendIgnoreCooldowns(coreAbil)) { - if (coreAbil instanceof AirAbility && bPlayer.isElementToggled(Element.AIR)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !plugin.getConfig().getBoolean("Properties.Air.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(AirBreath.class)) { - new AirBreath(player); - } - if (abilClass.equals(AirGlide.class)) { - new AirGlide(player); - } - if (abilClass.equals(Meditate.class)) { - new Meditate(player); - } - if (abilClass.equals(SonicBlast.class)) { - new SonicBlast(player); - } - } - - if (coreAbil instanceof EarthAbility && bPlayer.isElementToggled(Element.EARTH)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Earth.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(EarthKick.class)) { - new EarthKick(player); - } - if (abilClass.equals(EarthLine.class)) { - new EarthLine(player); - } - if (abilClass.equals(EarthPillar.class)) { - new EarthPillar(player); - } - if (abilClass.equals(EarthShard.class)) { - new EarthShard(player); - } - if (abilClass.equals(Fissure.class)) { - Fissure.performAction(player); - } - if (abilClass.equals(LavaDisc.class)) { - new LavaDisc(player); - } - if (abilClass.equals(MagnetShield.class)) { - new MagnetShield(player, false); - } - if (abilClass.equals(MetalFragments.class)) { - new MetalFragments(player); - } - if (abilClass.equals(MetalShred.class)) { - new MetalShred(player); - } - if (abilClass.equals(MudSurge.class)) { - new MudSurge(player); - } - if (abilClass.equals(SandBlast.class)) { - new SandBlast(player); - } - if (abilClass.equals(Crevice.class)) { - Crevice.closeCrevice(player); - } - } - - if (coreAbil instanceof FireAbility && bPlayer.isElementToggled(Element.FIRE)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Fire.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(Combustion.class)) { - new Combustion(event.getPlayer()); - } - if (abilClass.equals(FireBreath.class)) { - new FireBreath(player); - } - if (abilClass.equals(FireComet.class)) { - new FireComet(player); - } - if (abilClass.equals(FireJet.class)) { - if (FireSki.isPunchActivated(player.getWorld())) { - FireSki fs = CoreAbility.getAbility(player, FireSki.class); - - if (fs != null) { - fs.remove(); - } - } else { - new FireSki(player); - } - } - if (abilClass.equals(FireShots.class)) { - new FireShots(player); - } - if (abilClass.equals(LightningBurst.class)) { - new LightningBurst(player); - } - } - - if (coreAbil instanceof WaterAbility && bPlayer.isElementToggled(Element.WATER)) { - if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Water.CanBendWithWeapons")) { - return; - } - if (abilClass.equals(com.jedk1.jedcore.ability.waterbending.Bloodbending.class)) { - new com.jedk1.jedcore.ability.waterbending.Bloodbending(player); - } - if (abilClass.equals(BloodPuppet.class)) { - new BloodPuppet(player); - } - if (abilClass.equals(FrostBreath.class)) { - new FrostBreath(player); - } - if (abilClass.equals(IceClaws.class)) { - new IceClaws(player); - } - if (abilClass.equals(IceWall.class)) { - new IceWall(player); - } - if (abilName.equals("Drain")) { - new Drain(player); - } - if (abilClass.equals(WakeFishing.class)) { - new WakeFishing(player); - } - } - - if (coreAbil instanceof AvatarAbility) { - if (abilClass.equals(SpiritBeam.class)) { - new SpiritBeam(player); - } - } - } - } - - @EventHandler - public void onArrowHit(EntityDamageByEntityEvent event) { - if (event.getDamager().getType() == EntityType.ARROW) { - Arrow arrow = (Arrow) event.getDamager(); - if (arrow.getShooter() instanceof Player && arrow.hasMetadata("daggerthrow")){ - Player player = (Player) arrow.getShooter(); - player.playSound(player.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1f, 1); - } - } - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerInteraction(PlayerInteractEvent event) { - if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { - MetalFragments.shootFragment(event.getPlayer()); - } - } -} + JedCore plugin; + + public AbilityListener(JedCore plugin) { + this.plugin = plugin; + } + + private final List recentlyDropped = new ArrayList<>(); + + @EventHandler(priority = EventPriority.LOWEST) + // Abilities that should bypass punch cancels should be handled here. + public void onPlayerSwingBypassCancel(PlayerInteractEvent event) { + Player player = event.getPlayer(); + if (event.getHand() != EquipmentSlot.HAND) { + return; + } + if (event.getAction() != Action.LEFT_CLICK_BLOCK && event.getAction() != Action.LEFT_CLICK_AIR) { + return; + } + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); + if (bPlayer == null) { + return; + } + + if (Suffocate.isBreathbent(player) || bPlayer.isChiBlocked()) { + return; + } + + if (Bloodbending.isBloodbent(player) || MovementHandler.isStopped(player)) { + return; + } + + CoreAbility coreAbil = bPlayer.getBoundAbility(); + if (coreAbil == null) { + return; + } + + if (!bPlayer.canBendIgnoreCooldowns(coreAbil)) { + return; + } + + if (coreAbil instanceof FireAbility && bPlayer.isElementToggled(Element.FIRE)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Fire.CanBendWithWeapons")) { + return; + } + + // FireSki bypasses punch cancel because the normal version is activated from sneaking alone. + // The punch activation exists just so people don't accidentally activate it, so they should have the same + // requirements for activation. + if (coreAbil instanceof FireJet && FireSki.isPunchActivated(player.getWorld())) { + if (player.isSneaking()) { + FireSki ski = new FireSki(player); + if (ski.isStarted() && !bPlayer.isOnCooldown("FireJet")) { + // The event only needs to be cancelled when FireSki is set to have no cooldown. + // This is to prevent FireJet from activating from the same swing event. + event.setCancelled(true); + } + } + } + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerDropItemEvent(PlayerDropItemEvent event) { + recentlyDropped.add(event.getPlayer().getUniqueId()); + + // FirePunch item burn effect + Player player = event.getPlayer(); + FirePunch fp = FirePunch.getAbility(player, FirePunch.class); + boolean burnEnabled = com.jedk1.jedcore.configuration.JedCoreConfig.getConfig((Player)null).getBoolean("Abilities.Fire.FirePunch.BurnsDroppedItems", true); + if (fp != null && burnEnabled) { + var item = event.getItemDrop(); + var loc = fp.getRightHandPos(); + ParticleEffect.LAVA.display(loc, 5, 0.1, 0.1, 0.1, 0.05); + ParticleEffect.FLAME.display(loc, 3, 0.1, 0.1, 0.1, 0.01); + ParticleEffect.SMOKE_NORMAL.display(loc, 2, 0.05, 0.05, 0.05, 0.01); + loc.getWorld().playSound(loc, Sound.BLOCK_FIRE_EXTINGUISH, 0.3f, 1.4f); + ThreadUtil.ensureEntity(item, item::remove); + } + + ThreadUtil.runGlobalLater(() -> recentlyDropped.remove(event.getPlayer().getUniqueId()), 2L); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerInventoryInteract(InventoryClickEvent event) { + InventoryAction action = event.getAction(); + if (action == InventoryAction.DROP_ALL_CURSOR || + action == InventoryAction.DROP_ALL_SLOT || + action == InventoryAction.DROP_ONE_CURSOR || + action == InventoryAction.DROP_ONE_SLOT || + action == InventoryAction.UNKNOWN) { + + recentlyDropped.add(event.getWhoClicked().getUniqueId()); + + ThreadUtil.runGlobalLater(() -> { + recentlyDropped.remove(event.getWhoClicked().getUniqueId()); + }, 2L); + } + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerSwing(PlayerInteractEvent event) { + Player player = event.getPlayer(); + + if (recentlyDropped.contains(player.getUniqueId())) return; + + if (event.getHand() != EquipmentSlot.HAND) { + return; + } + if (event.getAction() != Action.LEFT_CLICK_BLOCK && event.getAction() != Action.LEFT_CLICK_AIR) { + return; + } + if (event.getAction() == Action.LEFT_CLICK_BLOCK && event.isCancelled()){ + return; + } + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); + if (bPlayer == null) { + return; + } + + if (Suffocate.isBreathbent(player)) { + event.setCancelled(true); + return; + } else if (Bloodbending.isBloodbent(player) || MovementHandler.isStopped(player)) { + event.setCancelled(true); + return; + } else if (bPlayer.isChiBlocked()) { + event.setCancelled(true); + return; + } else if (GeneralMethods.isInteractable(player.getTargetBlock((Set)null, 5))) { + return; + } + + if (bPlayer.isToggled()) { + new WallRun(player); + } + + CoreAbility coreAbil = bPlayer.getBoundAbility(); + if (coreAbil == null) { + if (MultiAbilityManager.hasMultiAbilityBound(player)){ + String abil = MultiAbilityManager.getBoundMultiAbility(player); + if (abil.equalsIgnoreCase("elementsphere")) { + new ElementSphere(player); + } + } + return; + } + + String abilName = bPlayer.getBoundAbilityName(); + Class abilClass = coreAbil.getClass(); + + if (bPlayer.canBendIgnoreCooldowns(coreAbil)) { + + if (coreAbil instanceof AirAbility && bPlayer.isElementToggled(Element.AIR)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Air.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(AirBlade.class)) { + new AirBlade(player); + } + if (abilClass.equals(AirPunch.class)) { + new AirPunch(player); + } + } + + if (coreAbil instanceof EarthAbility && bPlayer.isElementToggled(Element.EARTH)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Earth.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(EarthArmor.class)) { + new MetalArmor(player); + } + if (abilClass.equals(EarthLine.class)) { + EarthLine.shootLine(player); + } + if (abilClass.equals(EarthShard.class)) { + EarthShard.throwShard(player); + } + if (abilClass.equals(EarthSurf.class)) { + new EarthSurf(player); + } + if (abilClass.equals(Fissure.class)) { + new Fissure(player); + } + if (abilClass.equals(LavaFlux.class)) { + new LavaFlux(player); + } + if (abilClass.equals(LavaThrow.class)) { + LavaThrow lt = CoreAbility.getAbility(player, LavaThrow.class); + if (lt != null) { + lt.createBlast(); + } + } + if (abilClass.equals(MetalFragments.class)) { + MetalFragments.shootFragment(player); + } + if (abilClass.equals(MetalHook.class)) { + new MetalHook(player); + } + if (abilClass.equals(MetalShred.class)) { + MetalShred.extend(player); + } + if (abilClass.equals(MudSurge.class)) { + MudSurge.mudSurge(player); + } + if (abilClass.equals(SandBlast.class)) { + SandBlast.blastSand(player); + } + if (abilClass.equals(LavaFlow.class)) { + MagmaBlast.performAction(player); + } + if (abilClass.equals(MagnetShield.class)) { + new MagnetShield(player, true); + } + } + + if (coreAbil instanceof FireAbility && bPlayer.isElementToggled(Element.FIRE)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Fire.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(Combustion.class)) { + Combustion.combust(player); + } + if (abilClass.equals(Discharge.class)) { + new Discharge(player); + } + if (abilClass.equals(FireBall.class)) { + new FireBall(player); + } + if (abilClass.equals(FirePunch.class)) { + new FirePunch(player); + } + if (abilClass.equals(FireShots.class)) { + FireShots.fireShot(player); + } + } + + if (coreAbil instanceof WaterAbility && bPlayer.isElementToggled(Element.WATER)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.WATER.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(com.jedk1.jedcore.ability.waterbending.Bloodbending.class)) { + com.jedk1.jedcore.ability.waterbending.Bloodbending.launch(player); + } + if (abilClass.equals(BloodPuppet.class)) { + BloodPuppet.attack(player); + } + if (abilClass.equals(IceClaws.class)) { + IceClaws.throwClaws(player); + } + if (abilName.equals("Drain")) { + Drain.fireBlast(player); + } + if (coreAbil.getName().equalsIgnoreCase("watermanipulation")) { + WaterGimbal.prepareBlast(player); + } + if (coreAbil.getName().equalsIgnoreCase("watermanipulation")) { + WaterFlow.freeze(player); + } + } + if (coreAbil instanceof ChiAbility && bPlayer.isElementToggled(Element.CHI)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Chi.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(DaggerThrow.class)) { + new DaggerThrow(player); + } + } + + if (coreAbil instanceof AvatarAbility) { + if (abilClass.equals(ElementSphere.class)) { + new ElementSphere(player); + } + } + } + } + + public static ConcurrentHashMap recent = new ConcurrentHashMap(); + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onPlayerSneak(PlayerToggleSneakEvent event) { + Player player = event.getPlayer(); + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); + + if (event.isCancelled() || bPlayer == null) { + return; + } + + String abilName = bPlayer.getBoundAbilityName(); + if (Suffocate.isBreathbent(player)) { + if (!abilName.equalsIgnoreCase("AirSwipe") + && !abilName.equalsIgnoreCase("FireBlast") + && !abilName.equalsIgnoreCase("EarthBlast") + && !abilName.equalsIgnoreCase("WaterManipulation")) { + if(!player.isSneaking()) { + event.setCancelled(true); + } + } + } + + if (MovementHandler.isStopped(player) || Bloodbending.isBloodbent(player)) { + event.setCancelled(true); + return; + } + + CoreAbility coreAbil = bPlayer.getBoundAbility(); + if (coreAbil == null) { + return; + } + + Class abilClass = coreAbil.getClass(); + + if (bPlayer.isChiBlocked()) { + event.setCancelled(true); + return; + } + + if (player.isSneaking() && bPlayer.canBendIgnoreCooldowns(coreAbil)) { + if (coreAbil instanceof FireAbility && bPlayer.isElementToggled(Element.FIRE)) { + if (abilClass.equals(FireShots.class)) { + FireShots.swapHands(player); + } + + if (abilClass.equals(FirePunch.class)) { + FirePunch.swapHands(player); + } + } + } + + if (!player.isSneaking() && bPlayer.canBendIgnoreCooldowns(coreAbil)) { + if (coreAbil instanceof AirAbility && bPlayer.isElementToggled(Element.AIR)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !plugin.getConfig().getBoolean("Properties.Air.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(AirBreath.class)) { + new AirBreath(player); + } + if (abilClass.equals(AirGlide.class)) { + new AirGlide(player); + } + if (abilClass.equals(Meditate.class)) { + new Meditate(player); + } + if (abilClass.equals(SonicBlast.class)) { + new SonicBlast(player); + } + } + + if (coreAbil instanceof EarthAbility && bPlayer.isElementToggled(Element.EARTH)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Earth.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(EarthKick.class)) { + new EarthKick(player); + } + if (abilClass.equals(EarthLine.class)) { + new EarthLine(player); + } + if (abilClass.equals(EarthPillar.class)) { + new EarthPillar(player); + } + if (abilClass.equals(EarthShard.class)) { + new EarthShard(player); + } + if (abilClass.equals(Fissure.class)) { + Fissure.performAction(player); + } + if (abilClass.equals(LavaDisc.class)) { + new LavaDisc(player); + } + if (abilClass.equals(MagnetShield.class)) { + new MagnetShield(player, false); + } + if (abilClass.equals(MetalFragments.class)) { + new MetalFragments(player); + } + if (abilClass.equals(MetalShred.class)) { + new MetalShred(player); + } + if (abilClass.equals(MudSurge.class)) { + new MudSurge(player); + } + if (abilClass.equals(SandBlast.class)) { + new SandBlast(player); + } + if (abilClass.equals(Crevice.class)) { + Crevice.closeCrevice(player); + } + if (abilClass.equals(LavaThrow.class)) { + LavaThrow lt = CoreAbility.getAbility(player, LavaThrow.class); + if (lt == null) { + new LavaThrow(player); + } + } + } + + if (coreAbil instanceof FireAbility && bPlayer.isElementToggled(Element.FIRE)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Fire.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(Combustion.class)) { + new Combustion(event.getPlayer()); + } + if (abilClass.equals(FireBreath.class)) { + new FireBreath(player); + } + if (abilClass.equals(FireComet.class)) { + new FireComet(player); + } + if (abilClass.equals(FireJet.class)) { + if (FireSki.isPunchActivated(player.getWorld())) { + FireSki fs = CoreAbility.getAbility(player, FireSki.class); + + if (fs != null) { + ThreadUtil.ensureEntity(player, fs::remove); + } + } else { + new FireSki(player); + } + } + if (abilClass.equals(FireShots.class)) { + new FireShots(player); + } + if (abilClass.equals(LightningBurst.class)) { + new LightningBurst(player); + } + } + + if (coreAbil instanceof WaterAbility && bPlayer.isElementToggled(Element.WATER)) { + if (GeneralMethods.isWeapon(player.getInventory().getItemInMainHand().getType()) && !ProjectKorra.plugin.getConfig().getBoolean("Properties.Water.CanBendWithWeapons")) { + return; + } + if (abilClass.equals(com.jedk1.jedcore.ability.waterbending.Bloodbending.class)) { + new com.jedk1.jedcore.ability.waterbending.Bloodbending(player); + } + if (abilClass.equals(BloodPuppet.class)) { + new BloodPuppet(player); + } + if (abilClass.equals(FrostBreath.class)) { + new FrostBreath(player); + } + if (abilClass.equals(IceClaws.class)) { + new IceClaws(player); + IceClaws.swapHands(player); + } + if (abilClass.equals(IceWall.class)) { + new IceWall(player); + } + if (abilName.equals("Drain")) { + new Drain(player); + } + if (abilClass.equals(WakeFishing.class)) { + new WakeFishing(player); + } + } + + if (coreAbil instanceof AvatarAbility) { + if (abilClass.equals(SpiritBeam.class)) { + new SpiritBeam(player); + } + } + } + } + + @EventHandler + public void onArrowHit(EntityDamageByEntityEvent event) { + if (event.getDamager().getType() == EntityType.ARROW) { + Arrow arrow = (Arrow) event.getDamager(); + if (arrow.getShooter() instanceof Player && arrow.hasMetadata("daggerthrow")) { + Player player = (Player) arrow.getShooter(); + event.setDamage(0.0D); + player.playSound(player.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1.0f, 1.0f); + } + } + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerInteraction(PlayerInteractEvent event) { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { + MetalFragments.shootFragment(event.getPlayer()); + } + } + + @EventHandler + public void onChange(EntityChangeBlockEvent event) { + if (event.getEntity() instanceof FallingBlock) { + if (event.getEntity().hasMetadata("magmablast")) event.setCancelled(true); + } + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/listener/CommandListener.java b/src/com/jedk1/jedcore/listener/CommandListener.java index a5d879d..abdc6ca 100644 --- a/src/com/jedk1/jedcore/listener/CommandListener.java +++ b/src/com/jedk1/jedcore/listener/CommandListener.java @@ -4,79 +4,70 @@ import com.jedk1.jedcore.command.JedCoreCommand; import com.jedk1.jedcore.event.PKCommandEvent; import com.jedk1.jedcore.event.PKCommandEvent.CommandType; -import com.jedk1.jedcore.scoreboard.BendingBoard; +import com.jedk1.jedcore.util.ThreadUtil; import com.projectkorra.projectkorra.command.PKCommand; - import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.scheduler.BukkitRunnable; import java.util.Arrays; import java.util.UUID; public class CommandListener implements Listener { - JedCore plugin; - String[] cmdaliases = {"/bending", "/bend", "/b", "/pk", "/projectkorra", "/korra", "/mtla", "/tla"}; - public static String[] developers = { - "4eb6315e-9dd1-49f7-b582-c1170e497ab0", //jedk1 - "d57565a5-e6b0-44e3-a026-979d5de10c4d", //s3xi - "e98a2f7d-d571-4900-a625-483cbe6774fe", //Aztl - "b6bd2ceb-4922-4707-9173-8a02044e9069" //Cozmyc - }; + JedCore plugin; + String[] cmdaliases = {"/bending", "/bend", "/b", "/pk", "/projectkorra", "/korra", "/mtla", "/tla"}; + public static String[] developers = { + "4eb6315e-9dd1-49f7-b582-c1170e497ab0", //jedk1 + "d57565a5-e6b0-44e3-a026-979d5de10c4d", //s3xi + "e98a2f7d-d571-4900-a625-483cbe6774fe", //Aztl + "b6bd2ceb-4922-4707-9173-8a02044e9069", //Cozmyc + "b1318b21-5956-445c-a328-bad3175c1c7a" //Hihelloy + }; - public CommandListener(JedCore plugin) { - this.plugin = plugin; - } + public CommandListener(JedCore plugin) { + this.plugin = plugin; + } - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerCommand(PlayerCommandPreprocessEvent event) { - String cmd = event.getMessage().toLowerCase(); - String[] args = cmd.split("\\s+"); - if (Arrays.asList(cmdaliases).contains(args[0]) && args.length >= 2) { - PKCommandEvent new_event = new PKCommandEvent(event.getPlayer(), args, null); - for (PKCommand command : PKCommand.instances.values()) { - if (Arrays.asList(command.getAliases()).contains(args[1].toLowerCase())) { - new_event = new PKCommandEvent(event.getPlayer(), args, CommandType.getType(command.getName())); - } - } - Bukkit.getServer().getPluginManager().callEvent(new_event); - } - } + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerCommand(PlayerCommandPreprocessEvent event) { + String cmd = event.getMessage().toLowerCase(); + String[] args = cmd.split("\\s+"); + if (Arrays.asList(cmdaliases).contains(args[0]) && args.length >= 2) { + PKCommandEvent new_event = new PKCommandEvent(event.getPlayer(), args, null); + for (PKCommand command : PKCommand.instances.values()) { + if (Arrays.asList(command.getAliases()).contains(args[1].toLowerCase())) { + new_event = new PKCommandEvent(event.getPlayer(), args, CommandType.getType(command.getName())); + } + } + Bukkit.getServer().getPluginManager().callEvent(new_event); + } + } - CommandType[] types = {CommandType.ADD, CommandType.BIND, CommandType.CHOOSE, CommandType.CLEAR, CommandType.PRESET, CommandType.REMOVE}; + CommandType[] types = {CommandType.ADD, CommandType.BIND, CommandType.CHOOSE, CommandType.CLEAR, CommandType.PRESET, CommandType.REMOVE}; - @EventHandler(priority = EventPriority.NORMAL) - public void onPKCommand(final PKCommandEvent event) { - new BukkitRunnable() { - public void run() { - if (event.getType() != null) { - if (Arrays.asList(types).contains(event.getType())) { - Player player = event.getSender(); - if (BendingBoard.isDisabled(player)) return; - BendingBoard.get(player).update(); - } - if (event.getType().equals(CommandType.WHO) && event.getSender().hasPermission("bending.command.who")) { - if (event.getArgs().length == 3) { - if (Bukkit.getPlayer(event.getArgs()[2]) != null) { - UUID uuid = Bukkit.getPlayer(event.getArgs()[2]).getUniqueId(); - if (Arrays.asList(developers).contains(uuid.toString())) { - event.getSender().sendMessage(ChatColor.DARK_AQUA + "JedCore Developer"); - } - } - } - return; - } - if (event.getType().equals(CommandType.VERSION) && event.getSender().hasPermission("bending.command.version")) { - JedCoreCommand.sendBuildInfo(event.getSender()); - } - } - } - }.runTaskLater(JedCore.plugin, 1); - } -} + @EventHandler(priority = EventPriority.NORMAL) + public void onPKCommand(final PKCommandEvent event) { + ThreadUtil.runGlobalLater(() -> { + if (event.getType() != null) { + if (event.getType().equals(CommandType.WHO) && event.getSender().hasPermission("bending.command.who")) { + if (event.getArgs().length == 3) { + if (Bukkit.getPlayer(event.getArgs()[2]) != null) { + UUID uuid = Bukkit.getPlayer(event.getArgs()[2]).getUniqueId(); + if (Arrays.asList(developers).contains(uuid.toString())) { + event.getSender().sendMessage(ChatColor.DARK_AQUA + "JedCore Developer"); + } + } + } + return; + } + if (event.getType().equals(CommandType.VERSION) && event.getSender().hasPermission("bending.command.version")) { + JedCoreCommand.sendBuildInfo(event.getSender()); + } + } + }, 1); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/listener/JCListener.java b/src/com/jedk1/jedcore/listener/JCListener.java index 8eea29f..c17ba3a 100644 --- a/src/com/jedk1/jedcore/listener/JCListener.java +++ b/src/com/jedk1/jedcore/listener/JCListener.java @@ -11,15 +11,16 @@ import com.jedk1.jedcore.ability.firebending.FireSki; import com.jedk1.jedcore.ability.waterbending.IceClaws; import com.jedk1.jedcore.ability.waterbending.IceWall; -import com.jedk1.jedcore.scoreboard.BendingBoard; import com.jedk1.jedcore.util.LightManager; import com.jedk1.jedcore.util.RegenTempBlock; +import com.jedk1.jedcore.util.ThreadUtil; import com.projectkorra.projectkorra.ProjectKorra; import com.projectkorra.projectkorra.ability.CoreAbility; import com.projectkorra.projectkorra.ability.IceAbility; import com.projectkorra.projectkorra.earthbending.lava.LavaFlow; -import com.projectkorra.projectkorra.event.*; - +import com.projectkorra.projectkorra.event.AbilityStartEvent; +import com.projectkorra.projectkorra.event.BendingReloadEvent; +import com.projectkorra.projectkorra.event.HorizontalVelocityChangeEvent; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.waterbending.plant.PlantRegrowth; @@ -27,7 +28,9 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; -import org.bukkit.entity.*; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -38,267 +41,199 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.inventory.InventoryPickupItemEvent; -import org.bukkit.event.player.*; -import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerToggleSprintEvent; public class JCListener implements Listener { - JedCore plugin; - - public JCListener(JedCore plugin) { - this.plugin = plugin; - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerJoin(PlayerJoinEvent event) { - if (BendingBoard.isDisabled(event.getPlayer())) { - return; - } - BendingBoard bb = BendingBoard.get(event.getPlayer()); - if (bb != null) { - new BukkitRunnable() { - public void run() { - bb.update(); - } - }.runTaskLater(JedCore.plugin, 50); - } - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerQuit(PlayerQuitEvent event){ - BendingBoard bb = BendingBoard.get(event.getPlayer()); - if (bb != null) { - bb.remove(); - } - } - - @EventHandler - public void onAbilityStart(AbilityStartEvent event) { - if (event.isCancelled()) return; - - if (event.getAbility() instanceof LavaFlow) { - Player player = event.getAbility().getPlayer(); - MagmaBlast mb = CoreAbility.getAbility(player, MagmaBlast.class); - - if (mb != null && (mb.hasBlocks() || mb.shouldBlockLavaFlow())) { - event.setCancelled(true); - LavaFlow flow = (LavaFlow) event.getAbility(); - - // Reset the cooldown of LavaFlow that was set before the call to start(). - flow.getBendingPlayer().removeCooldown(flow); - } - } else if (event.getAbility() instanceof PlantRegrowth) { - PlantRegrowth regrowth = (PlantRegrowth)event.getAbility(); - - // Stop PlantRegrowth from creating permanent snow when used against FrostBreath snow. - if (regrowth.getType() == Material.SNOW && TempBlock.isTempBlock(regrowth.getBlock())) { - event.setCancelled(true); - } - } - } - - @EventHandler - public void onFlow(BlockFromToEvent event) { - if (!LavaDisc.canFlowFrom(event.getBlock())) { - event.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.LOW) - public void onPlayerFallDamage(EntityDamageEvent event) { - if (event.isCancelled() || event.getCause() != DamageCause.FALL || !(event.getEntity() instanceof Player)) { - return; - } - - Player player = (Player)event.getEntity(); - - if (MudSurge.onFallDamage(player)) { - event.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onEntityDamage(EntityDamageEvent event) { - if (event.getCause().equals(DamageCause.SUFFOCATION)) { - if (event.getEntity() instanceof LivingEntity) { - LivingEntity entity = (LivingEntity) event.getEntity(); - Block block = entity.getEyeLocation().getBlock(); - if (RegenTempBlock.blocks.containsKey(block) && IceAbility.isIce(block)) { - event.setCancelled(true); - return; - } - } - } - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { - if (event.getDamager() instanceof Player && event.getEntity() instanceof LivingEntity) { - if (event.getCause() == DamageCause.ENTITY_ATTACK && event.getDamager().getWorld().equals(event.getEntity().getWorld())) { - double distSq = event.getDamager().getLocation().distanceSquared(event.getEntity().getLocation()); - - // Only activate these in melee range - if (distSq <= 5 * 5) { - FirePunch fp = CoreAbility.getAbility((Player) event.getDamager(), FirePunch.class); - if (fp != null) { - fp.punch((LivingEntity) event.getEntity()); - event.setCancelled(true); - return; - } - - if (Backstab.punch((Player) event.getDamager(), (LivingEntity) event.getEntity())) { - event.setCancelled(true); - double damage = Backstab.getDamage(event.getDamager().getWorld()); - DamageHandler.damageEntity(event.getEntity(), (Player) event.getDamager(), damage, CoreAbility.getAbility("BackStab")); - return; - } - } - } - - if (IceClaws.freezeEntity((Player) event.getDamager(), (LivingEntity) event.getEntity())) { - event.setCancelled(true); - return; - } - } - - if (event.getDamager() instanceof Arrow) { - Arrow arrow = (Arrow) event.getDamager(); - - if (event.getEntity() instanceof LivingEntity) { - if (arrow.hasMetadata("daggerthrow") && arrow.getShooter() instanceof Player) { - if (event.getEntity().getEntityId() != ((Player) arrow.getShooter()).getEntityId()) { - DaggerThrow.damageEntityFromArrow(((LivingEntity) event.getEntity()), arrow); - } - event.setDamage(0); - event.setCancelled(true); - arrow.remove(); - arrow.removeMetadata("daggerthrow", JedCore.plugin); - } - - if (arrow.hasMetadata("metalhook")) { - arrow.remove(); - event.setDamage(0); - event.setCancelled(true); - arrow.removeMetadata("metalhook", JedCore.plugin); - } - } - } - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onBlockBreak(BlockBreakEvent event) { - MetalFragments.remove(event.getPlayer(), event.getBlock()); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onEntityExplode(EntityExplodeEvent event){ - if (IceWall.checkExplosions(event.getLocation(), event.getEntity())) { - event.blockList().clear(); - } - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onCollisionWithEntity(HorizontalVelocityChangeEvent event) { - if (event.getEntity().getWorld() != event.getInstigator().getWorld()) { - return; - } - IceWall.collisionDamage(event.getEntity(), event.getDistanceTraveled(), event.getDifference(), event.getInstigator()); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerSprint(PlayerToggleSprintEvent event) { - if (!event.isSprinting()) - return; - - if (CoreAbility.hasAbility(event.getPlayer(), EarthSurf.class)) { - event.setCancelled(true); - return; - } - - if (CoreAbility.hasAbility(event.getPlayer(), FireSki.class)) { - event.setCancelled(true); - return; - } - - MetalShred.startShred(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void projectKorraReload(BendingReloadEvent event) { - final CommandSender sender = event.getSender(); - LightManager.get().restart(); - // There's a PK bug where a new collision manager is set on reload without stopping the old task. - ProjectKorra.getCollisionManager().stopCollisionDetection(); - new BukkitRunnable() { - public void run() { - JCMethods.reload(); - sender.sendMessage(ChatColor.DARK_AQUA + "JedCore config reloaded."); - } - }.runTaskLater(JedCore.plugin, 1); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerItemHoldEvent(PlayerItemHeldEvent event) { - BendingBoard.update(event.getPlayer(), event.getNewSlot()); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onCooldownChange(PlayerCooldownChangeEvent event) { - if (event.getPlayer() == null) return; - - // Fix a bug in ProjectKorra 1.8.4 that keeps IceWave around forever. - // It will continuously add a cooldown to WaterWave, which makes this spam tasks / scoreboard updates. - // It also happens with FastSwim when the player is a waterbender. - if (BendingBoard.shouldIgnoreAbility(event.getAbility())) { - return; - } - new BukkitRunnable() { - public void run() { - BendingBoard.update(event.getPlayer()); - } - }.runTaskLater(JedCore.plugin, 1); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onWorldChange(PlayerChangedWorldEvent event){ - new BukkitRunnable() { - public void run() { - BendingBoard.update(event.getPlayer()); - } - }.runTaskLater(JedCore.plugin, 1); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onElementChange(PlayerChangeElementEvent event){ - if (event.getTarget() == null) return; - new BukkitRunnable() { - public void run() { - BendingBoard.update(event.getTarget()); - } - }.runTaskLater(JedCore.plugin, 1); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onChat(AsyncPlayerChatEvent event){ - Player player = event.getPlayer(); - String msg = event.getMessage(); - - if (msg.toLowerCase().contains("bring fire and light together as one and allow the breath of color")) { - FireBreath.toggleRainbowBreath(player, true); - event.setCancelled(true); - } - - if (msg.toLowerCase().contains("split the bond of fire and light and set the color free")) { - FireBreath.toggleRainbowBreath(player, false); - event.setCancelled(true); - } - - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onItemPickup(InventoryPickupItemEvent event) { - if (event.getItem().getPickupDelay() >= Short.MAX_VALUE) { - event.setCancelled(true); - } - } -} + JedCore plugin; + + public JCListener(JedCore plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onAbilityStart(AbilityStartEvent event) { + if (event.isCancelled()) return; + + if (event.getAbility() instanceof LavaFlow) { + Player player = event.getAbility().getPlayer(); + MagmaBlast mb = CoreAbility.getAbility(player, MagmaBlast.class); + + if (mb != null && (mb.hasBlocks() || mb.shouldBlockLavaFlow())) { + event.setCancelled(true); + LavaFlow flow = (LavaFlow) event.getAbility(); + + // Reset the cooldown of LavaFlow that was set before the call to start(). + flow.getBendingPlayer().removeCooldown(flow); + } + } else if (event.getAbility() instanceof PlantRegrowth) { + PlantRegrowth regrowth = (PlantRegrowth)event.getAbility(); + + // Stop PlantRegrowth from creating permanent snow when used against FrostBreath snow. + if (regrowth.getType() == Material.SNOW && TempBlock.isTempBlock(regrowth.getBlock())) { + event.setCancelled(true); + } + } + } + + @EventHandler + public void onFlow(BlockFromToEvent event) { + if (!LavaDisc.canFlowFrom(event.getBlock())) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void onPlayerFallDamage(EntityDamageEvent event) { + if (event.isCancelled() || event.getCause() != DamageCause.FALL || !(event.getEntity() instanceof Player)) { + return; + } + + Player player = (Player)event.getEntity(); + + if (MudSurge.onFallDamage(player)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onEntityDamage(EntityDamageEvent event) { + if (event.getCause().equals(DamageCause.SUFFOCATION)) { + if (event.getEntity() instanceof LivingEntity) { + LivingEntity entity = (LivingEntity) event.getEntity(); + Block block = entity.getEyeLocation().getBlock(); + if (RegenTempBlock.blocks.containsKey(block) && IceAbility.isIce(block)) { + event.setCancelled(true); + return; + } + } + } + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.getDamager() instanceof Player && event.getEntity() instanceof LivingEntity) { + if (event.getCause() == DamageCause.ENTITY_ATTACK && event.getDamager().getWorld().equals(event.getEntity().getWorld())) { + double distSq = event.getDamager().getLocation().distanceSquared(event.getEntity().getLocation()); + + // Only activate these in melee range + if (distSq <= 5 * 5) { + FirePunch fp = CoreAbility.getAbility((Player) event.getDamager(), FirePunch.class); + if (fp != null) { + fp.punch((LivingEntity) event.getEntity()); + event.setCancelled(true); + return; + } + + if (Backstab.punch((Player) event.getDamager(), (LivingEntity) event.getEntity())) { + event.setCancelled(true); + double damage = Backstab.getDamage(event.getDamager().getWorld()); + DamageHandler.damageEntity(event.getEntity(), (Player) event.getDamager(), damage, CoreAbility.getAbility("BackStab")); + return; + } + } + } + + if (IceClaws.freezeEntity((Player) event.getDamager(), (LivingEntity) event.getEntity())) { + event.setCancelled(true); + return; + } + } + + if (event.getDamager() instanceof Arrow arrow) { + if (event.getEntity() instanceof LivingEntity) { + if (arrow.hasMetadata("daggerthrow")) { + event.setDamage(0); + if (!(arrow.getShooter() instanceof Player shooter)) return; + if (!CoreAbility.hasAbility(shooter, DaggerThrow.class)) return; + DaggerThrow daggerThrow = CoreAbility.getAbility(shooter, DaggerThrow.class); + if (daggerThrow != null) { + daggerThrow.damageEntityFromArrow(((LivingEntity) event.getEntity()), arrow); + ThreadUtil.ensureEntity(arrow, arrow::remove); + event.setCancelled(true); + } + } + if (arrow.hasMetadata("metalhook")) { + event.setDamage(0); + ThreadUtil.ensureEntity(arrow, arrow::remove); + event.setCancelled(true); + } + } + } + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onBlockBreak(BlockBreakEvent event) { + MetalFragments.remove(event.getPlayer(), event.getBlock()); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onEntityExplode(EntityExplodeEvent event){ + if (IceWall.checkExplosions(event.getLocation(), event.getEntity())) { + event.blockList().clear(); + } + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onCollisionWithEntity(HorizontalVelocityChangeEvent event) { + if (event.getEntity().getWorld() != event.getInstigator().getWorld()) { + return; + } + IceWall.collisionDamage(event.getEntity(), event.getDistanceTraveled(), event.getDifference(), event.getInstigator()); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerSprint(PlayerToggleSprintEvent event) { + if (!event.isSprinting()) + return; + + if (CoreAbility.hasAbility(event.getPlayer(), EarthSurf.class)) { + event.setCancelled(true); + return; + } + + if (CoreAbility.hasAbility(event.getPlayer(), FireSki.class)) { + event.setCancelled(true); + return; + } + + MetalShred.startShred(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void projectKorraReload(BendingReloadEvent event) { + final CommandSender sender = event.getSender(); + LightManager.get().restart(); + // There's a PK bug where a new collision manager is set on reload without stopping the old task. + ProjectKorra.getCollisionManager().stopCollisionDetection(); + ThreadUtil.runGlobalLater(() -> { + JCMethods.reload(); + sender.sendMessage(ChatColor.DARK_AQUA + "JedCore config reloaded."); + }, 1); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onChat(AsyncPlayerChatEvent event){ + Player player = event.getPlayer(); + String msg = event.getMessage(); + + if (msg.toLowerCase().contains("bring fire and light together as one and allow the breath of color")) { + FireBreath.toggleRainbowBreath(player, true); + event.setCancelled(true); + } + + if (msg.toLowerCase().contains("split the bond of fire and light and set the color free")) { + FireBreath.toggleRainbowBreath(player, false); + event.setCancelled(true); + } + + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onItemPickup(InventoryPickupItemEvent event) { + if (event.getItem().getPickupDelay() >= Short.MAX_VALUE) { + event.setCancelled(true); + } + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/policies/removal/CompositeRemovalPolicy.java b/src/com/jedk1/jedcore/policies/removal/CompositeRemovalPolicy.java index 77eb59b..f9dbebf 100644 --- a/src/com/jedk1/jedcore/policies/removal/CompositeRemovalPolicy.java +++ b/src/com/jedk1/jedcore/policies/removal/CompositeRemovalPolicy.java @@ -10,17 +10,20 @@ import java.util.List; public class CompositeRemovalPolicy implements RemovalPolicy { - private List policies = new ArrayList<>(); - private CoreAbility ability; + private final List policies = new ArrayList<>(); + private final CoreAbility ability; public CompositeRemovalPolicy(CoreAbility ability, List policies) { - this.policies = policies; + if (policies != null) { + this.policies.addAll(policies); + } this.ability = ability; } public CompositeRemovalPolicy(CoreAbility ability, RemovalPolicy... policies) { - // Create as an ArrayList instead of fixed-sized so policies can be added/removed. - this.policies = new ArrayList<>(Arrays.asList(policies)); + if (policies != null) { + this.policies.addAll(Arrays.asList(policies)); + } this.ability = ability; } @@ -36,32 +39,40 @@ public boolean shouldRemove() { return false; } + /** + * Loads each policy’s configuration. + * Policies with no config or disabled ones are removed. + */ public void load(ConfigurationSection config, String prefix) { - if (this.policies.isEmpty()) return; + if (policies.isEmpty() || config == null) return; String pathPrefix = prefix + ".RemovalPolicy."; - // Load the configuration section for each policy and pass it to the load method. - for (Iterator iterator = policies.iterator(); iterator.hasNext(); ) { + Iterator iterator = policies.iterator(); + while (iterator.hasNext()) { RemovalPolicy policy = iterator.next(); ConfigurationSection section = config.getConfigurationSection(pathPrefix + policy.getName()); - if (section != null) { - boolean enabled = section.getBoolean("Enabled"); - - if (!enabled) { - iterator.remove(); - continue; - } + if (section == null) { + iterator.remove(); + continue; + } - policy.load(section); + if (!section.getBoolean("Enabled", true)) { + iterator.remove(); + continue; } + + policy.load(section); } } + /** + * Loads policy config using a convention: "Abilities.[Element].[AbilityName]" + */ @Override public void load(ConfigurationSection config) { - if (this.policies.isEmpty()) return; + if (config == null || this.policies.isEmpty()) return; Element element = ability.getElement(); if (element instanceof Element.SubElement) { @@ -69,15 +80,19 @@ public void load(ConfigurationSection config) { } String abilityName = ability.getName(); - load(config, "Abilities." + element.getName() + "." + abilityName); + String prefix = "Abilities." + element.getName() + "." + abilityName; + + load(config, prefix); } public void addPolicy(RemovalPolicy policy) { - this.policies.add(policy); + if (policy != null) { + this.policies.add(policy); + } } public void removePolicyType(Class type) { - policies.removeIf((policy) -> type.isAssignableFrom(policy.getClass())); + policies.removeIf(policy -> type.isAssignableFrom(policy.getClass())); } @Override diff --git a/src/com/jedk1/jedcore/scoreboard/BendingBoard.java b/src/com/jedk1/jedcore/scoreboard/BendingBoard.java deleted file mode 100644 index 3485d45..0000000 --- a/src/com/jedk1/jedcore/scoreboard/BendingBoard.java +++ /dev/null @@ -1,279 +0,0 @@ -package com.jedk1.jedcore.scoreboard; - -import java.io.File; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -import com.projectkorra.projectkorra.util.ChatUtil; -import net.md_5.bungee.api.ChatColor; -import org.bukkit.Bukkit; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; - -import com.jedk1.jedcore.JCMethods; -import com.jedk1.jedcore.configuration.Config; -import com.jedk1.jedcore.configuration.JedCoreConfig; -import com.projectkorra.projectkorra.BendingPlayer; -import com.projectkorra.projectkorra.ability.CoreAbility; -import com.projectkorra.projectkorra.ability.util.MultiAbilityManager; - -public class BendingBoard { - private static final List IGNORE_ABILITIES = Arrays.asList("WaterWave", "FastSwim"); - private static final String OTHER = "Other:"; - public static Map otherAbilities = new HashMap<>(); - public static ConcurrentHashMap boards = new ConcurrentHashMap<>(); - public static List disabled = new ArrayList<>(); - public static boolean enabled; - public static String title; - public static String pointer; - public static String empty; - public static String toggleOn; - public static String toggleOff; - public static String combo; - public static Config toggled; - public static boolean disabledworlds; - - static { - toggled = new Config(new File("/board/players.yml")); - - List uuids = toggled.getConfig().getStringList("Players"); - if (!uuids.isEmpty()) { - if (!uuids.get(0).matches("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[34][0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}")) { - toggled.getConfig().set("Players", new ArrayList()); - toggled.saveConfig(); - } else { - for (String s : uuids) { - disabled.add(UUID.fromString(s)); - } - } - } - setFields(); - } - - private Player player; - private SimpleScoreboard scoreboard; - - public BendingBoard(Player player) { - this.player = player; - this.scoreboard = new SimpleScoreboard(title); - boards.put(player, this); - } - - public static void setFields() { - enabled = JedCoreConfig.board.getConfig().getBoolean("Settings.Enabled"); - title = ChatUtil.color(JedCoreConfig.board.getConfig().getString("Settings.Title")); - pointer = ChatUtil.color(JedCoreConfig.board.getConfig().getString("Settings.Pointer")); - empty = ChatUtil.color(JedCoreConfig.board.getConfig().getString("Settings.EmptySlot")); - combo = ChatUtil.color(JedCoreConfig.board.getConfig().getString("Settings.Combos")); - toggleOn = ChatUtil.color(JedCoreConfig.board.getConfig().getString("Settings.Toggle.On")); - toggleOff = ChatUtil.color(JedCoreConfig.board.getConfig().getString("Settings.Toggle.Off")); - disabledworlds = JedCoreConfig.board.getConfig().getBoolean("Settings.Display.DisabledWorlds"); - } - - public static boolean shouldIgnoreAbility(String abilityName) { - if (abilityName == null) return false; - - return IGNORE_ABILITIES.contains(abilityName); - } - - public static void loadOtherCooldowns() { - ConfigurationSection section = JedCoreConfig.board.getConfig().getConfigurationSection("Settings.OtherCooldowns"); - - otherAbilities.clear(); - - for (String ability : section.getKeys(false)) { - ConfigurationSection abilitySection = section.getConfigurationSection(ability); - if (abilitySection == null) continue; - - boolean enabled = abilitySection.getBoolean("Enabled", true); - if (!enabled) continue; - - String colorString = abilitySection.getString("Color"); - ChatColor color = null; - - if (colorString != null) { - color = ChatColor.of(colorString); - } - - otherAbilities.put(ability, color); - } - } - - public static void updateOnline() { - if (!enabled) return; - for (Player player : Bukkit.getOnlinePlayers()) { - if (disabled.contains(player.getUniqueId())) continue; - if (!disabledworlds && JCMethods.getDisabledWorlds().contains(player.getWorld().getName())) continue; - BendingBoard.get(player).update(); - } - } - - public static void toggle(Player player) { - if (!enabled) return; - List uuids = new ArrayList<>(toggled.getConfig().getStringList("Players")); - if (uuids.contains(player.getUniqueId().toString())) { - uuids.remove(player.getUniqueId().toString()); - disabled.remove(player.getUniqueId()); - get(player).update(); - player.sendMessage(toggleOn); - } else { - uuids.add(player.getUniqueId().toString()); - disabled.add(player.getUniqueId()); - get(player).remove(); - player.sendMessage(toggleOff); - } - toggled.getConfig().set("Players", uuids); - toggled.saveConfig(); - } - - public static void update(Player player) { - update(player, -1); - } - - public static void update(Player player, int slot) { - if (!enabled) { - if (disabled.contains(player.getUniqueId())) return; - if (!boards.containsKey(player)) return; - get(player).remove(); - return; - } - if (disabled.contains(player.getUniqueId())) return; - if (!disabledworlds && JCMethods.getDisabledWorlds().contains(player.getWorld().getName())) { - if (boards.containsKey(player)) { - get(player).remove(); - } - return; - } - get(player).update(slot); - } - - public static BendingBoard get(Player player) { - if (!enabled) return null; - if (boards.containsKey(player)) { - return boards.get(player); - } else { - return new BendingBoard(player); - } - } - - public static boolean isDisabled(Player player) { - return !enabled || disabled.contains(player.getUniqueId()); - } - - public void remove() { - scoreboard.reset(); - boards.remove(player); - player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard()); - } - - public void update() { - update(-1); - } - - public void update(final int slot) { - if (!enabled) return; - - BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - if (bPlayer == null) return; - - // Check if the player removed their bending board. It's possible for the board to update after hidden. - if (boards.get(player) == null) { - player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard()); - return; - } - - HashMap abilities = bPlayer.getAbilities(); - - int currentSlot = slot; - if (currentSlot < 0) { - currentSlot = player.getInventory().getHeldItemSlot(); - } - - List formatted = new ArrayList<>(); - - for (int slotIndex = 1; slotIndex < 10; slotIndex++) { - CoreAbility currentAbility = CoreAbility.getAbility(abilities.get(slotIndex)); - String currentAbilityName = abilities.get(slotIndex); - StringBuilder sb = new StringBuilder(); - - if (currentSlot == (slotIndex - 1)) { - sb.append(pointer); - } - - if (abilities.containsKey(slotIndex) && currentAbility != null) { - for (String str : formatted) { - String stripped = ChatColor.stripColor(str).replace(pointer, ""); - - if (stripped.equalsIgnoreCase(currentAbilityName)) { - // Add a unique chat color to the beginning, so the ability doesn't override other slots in the map. - sb.append(ChatColor.getByChar((char) slotIndex)); - break; - } - } - - sb.append(currentAbility.getElement().getColor()); - - if (bPlayer.isOnCooldown(currentAbilityName)) { - sb.append(ChatColor.STRIKETHROUGH); - } - - sb.append(currentAbilityName); - } else { - if (abilities.containsKey(slotIndex) && MultiAbilityManager.hasMultiAbilityBound(player)) { - sb.append(abilities.get(slotIndex)); - } else { - sb.append(empty.replace("%", String.valueOf(slotIndex))); - } - } - formatted.add(sb.toString()); - } - boolean combo = false; - for (String ability : bPlayer.getCooldowns().keySet()) { - if (JCMethods.getCombos().contains(ability)) { - if (!combo) { - formatted.add(BendingBoard.combo); - } - - combo = true; - formatted.add("" + CoreAbility.getAbility(ability).getElement().getColor() + ChatColor.STRIKETHROUGH + ability); - } - } - - if (!otherAbilities.isEmpty()) { - boolean other = false; - for (String ability : bPlayer.getCooldowns().keySet()) { - if (!otherAbilities.containsKey(ability)) continue; - ChatColor color = otherAbilities.get(ability); - - if (!other) { - formatted.add(OTHER); - other = true; - } - - if (color == null) - color = getColor(ability); - formatted.add("" + color + ChatColor.STRIKETHROUGH + ability); - } - } - - if (scoreboard.get(-10, "") != null) { - for (int i = -9; i > -22; i--) { - scoreboard.remove(i, ""); - } - } - - for (String s : formatted) { - scoreboard.add(s, -(formatted.indexOf(s) + 1)); - } - - scoreboard.update(); - scoreboard.send(player); - } - - private ChatColor getColor(String abilityName) { - CoreAbility ability = CoreAbility.getAbility(abilityName); - if (ability != null) - return ability.getElement().getColor(); - return ChatColor.WHITE; - } -} diff --git a/src/com/jedk1/jedcore/scoreboard/SimpleScoreboard.java b/src/com/jedk1/jedcore/scoreboard/SimpleScoreboard.java deleted file mode 100644 index 40162fb..0000000 --- a/src/com/jedk1/jedcore/scoreboard/SimpleScoreboard.java +++ /dev/null @@ -1,237 +0,0 @@ -package com.jedk1.jedcore.scoreboard; - -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.bukkit.scoreboard.DisplaySlot; -import org.bukkit.scoreboard.Objective; -import org.bukkit.scoreboard.Score; -import org.bukkit.scoreboard.Scoreboard; -import org.bukkit.scoreboard.Team; - -import java.util.AbstractMap; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -public class SimpleScoreboard { - - private static Map cache = new HashMap<>(); - - private Scoreboard scoreboard; - private String title; - private Map scores; - private Objective obj; - private List teams; - private List removed; - private Set updated; - - public SimpleScoreboard(String title) { - this.scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); - this.title = ChatColor.translateAlternateColorCodes('&', title); - this.scores = new ConcurrentHashMap<>(); - this.teams = Collections.synchronizedList(Lists.newArrayList()); - this.removed = Lists.newArrayList(); - this.updated = Collections.synchronizedSet(new HashSet<>()); - } - - public void add(String text, Integer score) { - text = ChatColor.translateAlternateColorCodes('&', text); - String stripped = ChatColor.stripColor(text); - - // Use the first 16 real characters. - if (stripped.length() > 16) { - int formatCounts = 0; - for (int i = 0; i < text.length(); ++i) { - if (text.charAt(i) == ChatColor.COLOR_CHAR) { - ++formatCounts; - } - } - - text = text.substring(0, Math.min(15 + formatCounts * 2, text.length())); - } - - if (remove(score, text, false) || !scores.containsValue(score)) { - updated.add(text); - } - - scores.put(text, score); - } - - public boolean remove(Integer score, String text) { - return remove(score, text, true); - } - - public boolean remove(Integer score, String n, boolean b) { - String toRemove = get(score, n); - - if (toRemove == null) - return false; - - scores.remove(toRemove); - - if(b) - removed.add(score); - - return true; - } - - public String get(int score, String n) { - String str = null; - - for (Map.Entry entry : scores.entrySet()) { - if (entry.getValue().equals(score) && - !entry.getKey().equals(n)) { - str = entry.getKey(); - } - } - - return str; - } - - private Map.Entry createTeam(String text, int pos) { - Team team; - ChatColor color = ChatColor.values()[(pos < 0) ? -pos : pos]; - String result; - - if (!cache.containsKey(color.toString())) - cache.put(color.toString(), color.toString()); - - result = cache.get(color.toString()); - - try { - team = scoreboard.registerNewTeam("text-" + (teams.size() + 1)); - } catch (IllegalArgumentException e) { - team = scoreboard.getTeam("text-" + (teams.size())); - } - - applyText(team, text, result); - - teams.add(team); - return new AbstractMap.SimpleEntry<>(team, result); - } - - private void applyText(Team team, String text, String result) { - Iterator iterator = Splitter.fixedLength(16).split(text).iterator(); - String prefix = iterator.next(); - - team.setPrefix(prefix); - - if(!team.hasEntry(result)) - team.addEntry(result); - - if (text.length() > 16) { - String prefixColor = ChatColor.getLastColors(prefix); - String suffix = iterator.next(); - - if (prefix.endsWith(String.valueOf(ChatColor.COLOR_CHAR))) { - prefix = prefix.substring(0, prefix.length() - 1); - team.setPrefix(prefix); - prefixColor = ChatColor.getByChar(suffix.charAt(0)).toString(); - suffix = suffix.substring(1); - } - - if (prefixColor == null) - prefixColor = ""; - - if (suffix.length() > 16) { - suffix = suffix.substring(0, (13 - prefixColor.length())); // cut off suffix, done if text is over 30 characters - } - - team.setSuffix((prefixColor.equals("") ? ChatColor.RESET : prefixColor) + suffix); - } - } - - public void update() { - if (updated.isEmpty()) { - return; - } - - if (obj == null) { - obj = scoreboard.registerNewObjective((title.length() > 16 ? title.substring(0, 15) : title), "dummy", (title.length() > 16 ? title.substring(0, 15) : title)); - obj.setDisplayName(title); - obj.setDisplaySlot(DisplaySlot.SIDEBAR); - } - - for (Integer aRemoved : removed) { - for (String s : scoreboard.getEntries()) { - Score score = obj.getScore(s); - - if (score == null) - continue; - - if (score.getScore() != aRemoved) - continue; - - scoreboard.resetScores(s); - } - } - - removed.clear(); - - int index = scores.size(); - - for (Map.Entry text : scores.entrySet()) { - Team t = scoreboard.getTeam(ChatColor.values()[(text.getValue() < 0) ? -text.getValue() : text.getValue()].toString()); - Map.Entry team; - - if(!updated.contains(text.getKey())) { - continue; - } - - if(t != null) { - String color = ChatColor.values()[(text.getValue() < 0) ? -text.getValue() : text.getValue()].toString(); - - if (!cache.containsKey(color)) { - cache.put(color, color); - } - - team = new AbstractMap.SimpleEntry<>(t, cache.get(color)); - applyText(team.getKey(), text.getKey(), team.getValue()); - index -= 1; - - continue; - } else { - team = createTeam(text.getKey(), text.getValue()); - } - - Integer score = text.getValue() != null ? text.getValue() : index; - - obj.getScore(team.getValue()).setScore(score); - index -= 1; - } - - updated.clear(); - } - - public void setTitle(String title) { - this.title = ChatColor.translateAlternateColorCodes('&', title); - - if(obj != null) - obj.setDisplayName(title); - } - - public void reset() { - for (Team t : teams) - t.unregister(); - teams.clear(); - scores.clear(); - } - - public Scoreboard getScoreboard() { - return scoreboard; - } - - public void send(Player... players) { - for (Player p : players) - p.setScoreboard(scoreboard); - } -} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/util/AbilitySelector.java b/src/com/jedk1/jedcore/util/AbilitySelector.java index fb1a8f5..5ce3da1 100644 --- a/src/com/jedk1/jedcore/util/AbilitySelector.java +++ b/src/com/jedk1/jedcore/util/AbilitySelector.java @@ -5,7 +5,9 @@ import com.projectkorra.projectkorra.earthbending.*; import com.projectkorra.projectkorra.firebending.*; import com.projectkorra.projectkorra.waterbending.*; -import com.projectkorra.projectkorra.waterbending.ice.*; +import com.projectkorra.projectkorra.waterbending.ice.IceSpikeBlast; +import com.projectkorra.projectkorra.waterbending.ice.IceSpikePillar; +import com.projectkorra.projectkorra.waterbending.ice.IceSpikePillarField; import java.util.HashMap; import java.util.Map; @@ -49,4 +51,4 @@ public static CoreAbility getAbility(String abilityName) { return CoreAbility.getAbility(abilityName); } -} +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/util/ChiRestrictor.java b/src/com/jedk1/jedcore/util/ChiRestrictor.java index 8869cc8..5b34e98 100644 --- a/src/com/jedk1/jedcore/util/ChiRestrictor.java +++ b/src/com/jedk1/jedcore/util/ChiRestrictor.java @@ -1,6 +1,5 @@ package com.jedk1.jedcore.util; -import com.jedk1.jedcore.JedCore; import com.jedk1.jedcore.configuration.JedCoreConfig; import com.projectkorra.projectkorra.ability.ChiAbility; import com.projectkorra.projectkorra.event.AbilityStartEvent; @@ -10,7 +9,6 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.scheduler.BukkitRunnable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -35,11 +33,9 @@ public class ChiRestrictor implements Listener { @EventHandler public void onBendingReload(BendingReloadEvent event) { - new BukkitRunnable() { - public void run() { - reloadConfig(); - } - }.runTaskLater(JedCore.plugin, 1); + ThreadUtil.runGlobalLater(() -> { + reloadConfig(); + }, 1); } public static void reloadConfig() { @@ -133,4 +129,4 @@ private static Entity getTarget(ChiAbility ability) { return null; } } -} +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/util/LightManager.java b/src/com/jedk1/jedcore/util/LightManager.java index a48727d..f9b5a3f 100644 --- a/src/com/jedk1/jedcore/util/LightManager.java +++ b/src/com/jedk1/jedcore/util/LightManager.java @@ -1,7 +1,6 @@ package com.jedk1.jedcore.util; import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ProjectKorra; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -30,8 +29,6 @@ public class LightManager { // Default LIGHT BlockData private final Map lightDataMap = new HashMap<>(); private final Map waterloggedLightDataMap = new HashMap<>(); - - // Scheduler with threads equal to the number of available processors, this handles reverting expired lights private ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors()); /** @@ -57,7 +54,7 @@ private LightManager() { /** * Retrieves the current time and iterates over all light data in the light map. If the current time is greater * than or equal to the expiry time of a light data, it fades the light out and removes the light data from the map. - * This is running periodically, or every 50ms, via the scheduled thread pool executor. + * This runs periodically via SchedulerUtil for Folia compatibility. */ private void revertExpiredLights() { long currentTime = System.currentTimeMillis(); @@ -111,7 +108,10 @@ private void startLightReverter() { scheduler = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors()); } - scheduler.scheduleAtFixedRate(this::revertExpiredLights, 0, 50, TimeUnit.MILLISECONDS); + // Use SchedulerUtil for main thread tasks (revertExpiredLights) + ThreadUtil.runGlobalTimer(this::revertExpiredLights, 0, 1); + + // Use ScheduledThreadPoolExecutor for client-side operations (sendBlockChange) scheduler.scheduleAtFixedRate(this::processBlockChanges, 0, 50, TimeUnit.MILLISECONDS); } @@ -123,28 +123,22 @@ private void startLightReverter() { */ private void fadeLight(LightData lightData) { int brightness = lightData.brightness; + fadeLightRecursive(lightData, brightness); + } - class TaskHolder { - ScheduledFuture future; + private void fadeLightRecursive(LightData lightData, int currentBrightness) { + if (currentBrightness <= 0) { + revertLight(lightData); + return; } - TaskHolder taskHolder = new TaskHolder(); - - Runnable task = new Runnable() { - private int currentBrightness = brightness; - - @Override - public void run() { - currentBrightness--; - if (currentBrightness > 0) { - sendLightChange(lightData.location, currentBrightness, lightData.observers); - } else { - revertLight(lightData); - taskHolder.future.cancel(false); - } - } - }; - taskHolder.future = scheduler.scheduleAtFixedRate(task, 0, 50, TimeUnit.MILLISECONDS); + // Process the light change (client-side only) + sendLightChange(lightData.location, currentBrightness, lightData.observers); + + // Schedule next fade step using the thread pool + scheduler.schedule(() -> { + fadeLightRecursive(lightData, currentBrightness - 1); + }, 50, TimeUnit.MILLISECONDS); } /** @@ -170,9 +164,8 @@ private void processBlockChanges() { while ((blockChange = blockChangeQueue.poll()) != null) { Player player = blockChange.getPlayer(); BlockChange finalBlockChange = blockChange; - Bukkit.getScheduler().runTaskAsynchronously(ProjectKorra.plugin, () -> { - player.sendBlockChange(finalBlockChange.getLocation(), finalBlockChange.getBlockData()); - }); + // sendBlockChange is client-side only, so we can call it directly from the thread pool + player.sendBlockChange(finalBlockChange.getLocation(), finalBlockChange.getBlockData()); } } diff --git a/src/com/jedk1/jedcore/util/LightManagerUtil.java b/src/com/jedk1/jedcore/util/LightManagerUtil.java new file mode 100644 index 0000000..e098afc --- /dev/null +++ b/src/com/jedk1/jedcore/util/LightManagerUtil.java @@ -0,0 +1,108 @@ +package com.jedk1.jedcore.util; + +import com.jedk1.jedcore.configuration.JedCoreConfig; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.util.Collection; + +public class LightManagerUtil { + + private static final boolean PROJECTKORRA_LIGHTMANAGER_AVAILABLE; + + static { + boolean available = false; + try { + Class.forName("com.projectkorra.projectkorra.util.LightManager"); + available = true; + } catch (ClassNotFoundException e) { + // ProjectKorra LightManager not available, fallback to built-in LightManager + } + PROJECTKORRA_LIGHTMANAGER_AVAILABLE = available; + } + + public static void emitFirebendingLight(final Location location) { + if (!JedCoreConfig.getConfig((Player)null).getBoolean("Properties.Fire.DynamicLight.Enabled")) { + return; + } + + int brightness = JedCoreConfig.getConfig((Player)null).getInt("Properties.Fire.DynamicLight.Brightness"); + long keepAlive = JedCoreConfig.getConfig((Player)null).getLong("Properties.Fire.DynamicLight.KeepAlive"); + + if (brightness < 1 || brightness > 15) { + throw new IllegalArgumentException("Properties.Fire.DynamicLight.Brightness must be between 1 and 15."); + } + + createLight(location).brightness(brightness).timeUntilFadeout(keepAlive).emit(); + } + + public static LightBuilder createLight(Location location) { + return new LightBuilder(location); + } + + public static boolean isProjectKorraLightManagerAvailable() { + return PROJECTKORRA_LIGHTMANAGER_AVAILABLE; + } + + public static class LightBuilder { + private final Location location; + private int brightness = 15; // default brightness + private long timeUntilFade = 50; // default expiry time in ms + private Collection observers = null; // null means all players + + public LightBuilder(Location location) { + this.location = location; + } + + public LightBuilder brightness(int brightness) { + this.brightness = Math.max(1, Math.min(15, brightness)); + return this; + } + + public LightBuilder timeUntilFadeout(long expiry) { + this.timeUntilFade = expiry; + return this; + } + + public LightBuilder observers(Collection observers) { + this.observers = observers; + return this; + } + + public void emit() { + if (PROJECTKORRA_LIGHTMANAGER_AVAILABLE) { + emitWithProjectKorraLightManager(); + } else { + emitWithJedCoreLightManager(); + } + } + + private void emitWithProjectKorraLightManager() { + try { + com.projectkorra.projectkorra.util.LightManager.LightBuilder lightBuilder = + com.projectkorra.projectkorra.util.LightManager.createLight(location); + + lightBuilder = lightBuilder.brightness(brightness); + lightBuilder = lightBuilder.timeUntilFadeout(timeUntilFade); + + if (observers != null) { + lightBuilder = lightBuilder.observers(observers); + } + + lightBuilder.emit(); + + } catch (Exception e) { + // Fallback to JedCore's LightManager if ProjectKorra's fails + emitWithJedCoreLightManager(); + } + } + + private void emitWithJedCoreLightManager() { + if (observers != null) { + LightManager.get().createLight(location).brightness(brightness).timeUntilFadeout(timeUntilFade).observers(observers).emit(); + } else { + LightManager.get().createLight(location).brightness(brightness).timeUntilFadeout(timeUntilFade).emit(); + } + } + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/util/MaterialUtil.java b/src/com/jedk1/jedcore/util/MaterialUtil.java index b3c60bd..527a153 100644 --- a/src/com/jedk1/jedcore/util/MaterialUtil.java +++ b/src/com/jedk1/jedcore/util/MaterialUtil.java @@ -1,7 +1,6 @@ package com.jedk1.jedcore.util; import com.projectkorra.projectkorra.GeneralMethods; - import org.bukkit.Material; import org.bukkit.Tag; import org.bukkit.block.Block; @@ -11,11 +10,13 @@ import java.util.List; public class MaterialUtil { + + // todo: use the registry/tags (with config) or grab directly from PKs config maybe? private static final List TRANSPARENT_MATERIALS = new ArrayList(){{ addAll(Arrays.asList( Material.AIR, Material.VOID_AIR, Material.CAVE_AIR, Material.OAK_SAPLING, Material.SPRUCE_SAPLING, Material.BIRCH_SAPLING, Material.JUNGLE_SAPLING, Material.ACACIA_SAPLING, Material.DARK_OAK_SAPLING, Material.WATER, - Material.LAVA, Material.COBWEB, Material.TALL_GRASS, Material.GRASS_BLOCK, Material.FERN, Material.DEAD_BUSH, + Material.LAVA, Material.COBWEB, Material.TALL_GRASS, Material.GRASS, Material.FERN, Material.DEAD_BUSH, Material.DANDELION, Material.POPPY, Material.BLUE_ORCHID, Material.ALLIUM, Material.AZURE_BLUET, Material.RED_TULIP, Material.ORANGE_TULIP, Material.WHITE_TULIP, Material.PINK_TULIP, Material.OXEYE_DAISY, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM, Material.TORCH, Material.FIRE, diff --git a/src/com/jedk1/jedcore/util/MetricsLite.java b/src/com/jedk1/jedcore/util/MetricsLite.java index b93fb90..46153ed 100644 --- a/src/com/jedk1/jedcore/util/MetricsLite.java +++ b/src/com/jedk1/jedcore/util/MetricsLite.java @@ -28,6 +28,7 @@ package com.jedk1.jedcore.util; +import com.cjcrafter.foliascheduler.bukkit.BukkitTask; import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.configuration.InvalidConfigurationException; @@ -35,15 +36,8 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; -import org.bukkit.scheduler.BukkitTask; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; + +import java.io.*; import java.lang.reflect.Method; import java.net.Proxy; import java.net.URL; @@ -110,7 +104,7 @@ public class MetricsLite { /** * Id of the scheduled task */ - private volatile BukkitTask task = null; + private volatile Object task = null; public MetricsLite(Plugin plugin) throws IOException { if (plugin == null) { @@ -159,7 +153,7 @@ public boolean start() { } // Begin hitting the server with glorious data - task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { + task = ThreadUtil.runAsyncTimer(new Runnable() { private boolean firstPost = true; @@ -169,7 +163,6 @@ public void run() { synchronized (optOutLock) { // Disable Task, if it is running and the server owner decided to opt-out if (isOptOut() && task != null) { - task.cancel(); task = null; } } @@ -251,7 +244,6 @@ public void disable() throws IOException { // Disable Task, if it is running if (task != null) { - task.cancel(); task = null; } } @@ -273,10 +265,10 @@ public File getConfigFile() { // return => base/plugins/PluginMetrics/config.yml return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml"); } - + /** * Gets the online player (backwards compatibility) - * + * * @return online player amount */ private int getOnlinePlayers() { @@ -292,7 +284,7 @@ private int getOnlinePlayers() { Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); } } - + return 0; } diff --git a/src/com/jedk1/jedcore/util/RegenTempBlock.java b/src/com/jedk1/jedcore/util/RegenTempBlock.java index 56794f6..adbaf62 100644 --- a/src/com/jedk1/jedcore/util/RegenTempBlock.java +++ b/src/com/jedk1/jedcore/util/RegenTempBlock.java @@ -2,7 +2,6 @@ import com.projectkorra.projectkorra.earthbending.passive.DensityShift; import com.projectkorra.projectkorra.util.TempBlock; - import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; diff --git a/src/com/jedk1/jedcore/util/TempFallingBlock.java b/src/com/jedk1/jedcore/util/TempFallingBlock.java new file mode 100644 index 0000000..f2eb206 --- /dev/null +++ b/src/com/jedk1/jedcore/util/TempFallingBlock.java @@ -0,0 +1,152 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package com.jedk1.jedcore.util; + +import com.projectkorra.projectkorra.ability.CoreAbility; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.FallingBlock; +import org.bukkit.util.Vector; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +public class TempFallingBlock { + public static ConcurrentHashMap instances = new ConcurrentHashMap(); + public static ConcurrentHashMap> instancesByAbility = new ConcurrentHashMap(); + private FallingBlock fallingblock; + private CoreAbility ability; + private long creation; + private boolean expire; + private Consumer onPlace; + + public TempFallingBlock(Location location, BlockData data, Vector velocity, CoreAbility ability) { + this(location, data, velocity, ability, false); + } + + public TempFallingBlock(Location location, BlockData data, Vector velocity, CoreAbility ability, boolean expire) { + this.fallingblock = location.getWorld().spawnFallingBlock(location, data.clone()); + this.fallingblock.setVelocity(velocity); + this.fallingblock.setDropItem(false); + this.ability = ability; + this.creation = System.currentTimeMillis(); + this.expire = expire; + instances.put(this.fallingblock, this); + if (!instancesByAbility.containsKey(ability)) { + instancesByAbility.put(ability, new HashSet()); + } + + ((Set)instancesByAbility.get(ability)).add(this); + } + + public static void manage() { + long time = System.currentTimeMillis(); + + for(TempFallingBlock tfb : instances.values()) { + if (tfb.canExpire() && time > tfb.getCreationTime() + 5000L) { + tfb.remove(); + } else if (time > tfb.getCreationTime() + 120000L) { + tfb.remove(); + } + } + + } + + public static TempFallingBlock get(FallingBlock fallingblock) { + return isTempFallingBlock(fallingblock) ? (TempFallingBlock)instances.get(fallingblock) : null; + } + + public static boolean isTempFallingBlock(FallingBlock fallingblock) { + return instances.containsKey(fallingblock); + } + + public static void removeFallingBlock(FallingBlock fallingblock) { + if (isTempFallingBlock(fallingblock)) { + TempFallingBlock tempFallingBlock = (TempFallingBlock)instances.get(fallingblock); + Objects.requireNonNull(fallingblock); + ThreadUtil.ensureEntity(fallingblock, fallingblock::remove); + instances.remove(fallingblock); + ((Set)instancesByAbility.get(tempFallingBlock.ability)).remove(tempFallingBlock); + if (((Set)instancesByAbility.get(tempFallingBlock.ability)).isEmpty()) { + instancesByAbility.remove(tempFallingBlock.ability); + } + } + + } + + public static void removeAllFallingBlocks() { + for(FallingBlock fallingblock : instances.keySet()) { + Objects.requireNonNull(fallingblock); + ThreadUtil.ensureEntity(fallingblock, fallingblock::remove); + } + + instances.clear(); + instancesByAbility.clear(); + } + + public static Set getFromAbility(CoreAbility ability) { + return (Set)instancesByAbility.getOrDefault(ability, new HashSet()); + } + + public void remove() { + FallingBlock var10000 = this.fallingblock; + FallingBlock var10001 = this.fallingblock; + Objects.requireNonNull(var10001); + ThreadUtil.ensureEntity(var10000, var10001::remove); + instances.remove(this.fallingblock); + } + + public FallingBlock getFallingBlock() { + return this.fallingblock; + } + + public CoreAbility getAbility() { + return this.ability; + } + + public Material getMaterial() { + return this.fallingblock.getBlockData().getMaterial(); + } + + public BlockData getMaterialData() { + return this.fallingblock.getBlockData(); + } + + public BlockData getData() { + return this.fallingblock.getBlockData(); + } + + public Location getLocation() { + return this.fallingblock.getLocation(); + } + + public long getCreationTime() { + return this.creation; + } + + public boolean canExpire() { + return this.expire; + } + + public void tryPlace() { + if (this.onPlace != null) { + this.onPlace.accept(this); + } + + } + + public Consumer getOnPlace() { + return this.onPlace; + } + + public void setOnPlace(Consumer onPlace) { + this.onPlace = onPlace; + } +} diff --git a/src/com/jedk1/jedcore/util/TemporaryFallingBlock.java b/src/com/jedk1/jedcore/util/TemporaryFallingBlock.java index 55debfb..3a21650 100644 --- a/src/com/jedk1/jedcore/util/TemporaryFallingBlock.java +++ b/src/com/jedk1/jedcore/util/TemporaryFallingBlock.java @@ -1,7 +1,6 @@ package com.jedk1.jedcore.util; import com.projectkorra.projectkorra.ability.CoreAbility; -import com.projectkorra.projectkorra.util.TempFallingBlock; import org.bukkit.Location; import org.bukkit.block.data.BlockData; import org.bukkit.util.Vector; diff --git a/src/com/jedk1/jedcore/util/ThreadUtil.java b/src/com/jedk1/jedcore/util/ThreadUtil.java new file mode 100644 index 0000000..e700175 --- /dev/null +++ b/src/com/jedk1/jedcore/util/ThreadUtil.java @@ -0,0 +1,376 @@ +package com.jedk1.jedcore.util; + + + + +import com.cjcrafter.foliascheduler.TaskImplementation; +import com.cjcrafter.foliascheduler.folia.FoliaTask; +import com.jedk1.jedcore.JedCore; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import java.util.logging.Level; + +import static com.jedk1.jedcore.JedCore.*; + + +/** + * Utility class for ensuring that a task is run on the correct thread. + * Ensures compatibility between Folia and non-Folia servers. */ +public class ThreadUtil { + + private static AtomicBoolean SHUTTING_DOWN = new AtomicBoolean(false); + + public ThreadUtil(Plugin plugin) { + + } + + /** + * Runs a task on the same thread as an entity. On Spigot, this is the main + * thread. On Folia, this is the thread that the entity is on.

+ * + * @param entity The entity to run the task on. + * @param runnable The task to run. + */ + public static void ensureEntity(@NotNull Entity entity, @NotNull Runnable runnable) { + if (entity instanceof Player && !((Player)entity).isOnline()) return; + + if (isFolia()) { + if (scheduler.isOwnedByCurrentRegion(entity) || SHUTTING_DOWN.get()) { + runCatch(runnable, "Error in ensureEntity task on shutdown"); + return; + } + scheduler.entity(entity).execute(runnable, null, 1L); + } else { + if (Bukkit.isPrimaryThread()) { + runCatch(runnable, "Error in ensureEntity task"); + return; + } + Bukkit.getScheduler().runTask(plugin, runnable); + } + } + + /** + * Runs a task on the same thread as an entity after a delay. On Spigot, this is the main + * thread. On Folia, this is the thread that the entity is on. + * @param entity The entity to run the task on. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @return The task object that can be used to cancel the task. Is a + * {@link FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static Object ensureEntityLater(@NotNull Entity entity, @NotNull Runnable runnable, long delay) { + if (entity instanceof Player && !((Player)entity).isOnline()) return null; + delay = Math.max(1, delay); + if (isFolia()) { + return scheduler.entity(entity).execute(runnable, null, delay); + } else { + return Bukkit.getScheduler().runTaskLater(plugin, runnable, delay); + } + } + + /** + * Runs a task on the same thread as an entity after a delay and repeats it until cancelled. + * On Spigot, this is the main thread. On Folia, this is the thread that the entity is on. + * @param entity The entity to run the task on. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @param repeat The delay in ticks between each repeat of the task. + * @return The task object that can be used to cancel the task. Is a + * {@link FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static Object ensureEntityTimer(@NotNull Entity entity, @NotNull Runnable runnable, long delay, long repeat) { + if (entity instanceof Player && !((Player)entity).isOnline()) return null; + delay = Math.max(1, delay); + repeat = Math.max(1, repeat); + if (isFolia()) { + return scheduler.entity(entity).runAtFixedRate((task) -> { + if (!runCatch(runnable, "Error in ensureEntityTimer task")) { + task.cancel(); + } + }, null, delay, repeat); + } else { + return Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, repeat); + } + } + + /** + * Runs a task on the same thread as a location. On Spigot, this is the main + * thread. On Folia, this is the thread that the location is in. + * @param location The location to run the task on. + * @param runnable The task to run. + */ + public static void ensureLocation(@NotNull Location location, @NotNull Runnable runnable) { + if (isFolia()) { + if (scheduler.isOwnedByCurrentRegion(location) || SHUTTING_DOWN.get()) { + runCatch(runnable, "Error in ensureLocation task on shutdown"); + return; + } + + scheduler.region(location).execute(runnable); + } else { + if (Bukkit.isPrimaryThread()) { + runCatch(runnable, "Error in ensureLocation task on shutdown"); + return; + } + Bukkit.getScheduler().runTask(plugin, runnable); + } + } + + /** + * Runs a task on the same thread as a location after a delay. On Spigot, this is the main + * thread. On Folia, this is the thread that the location is in. + * @param location The location to run the task on. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @return The task object that can be used to cancel the task. Is a + * {@link FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object ensureLocationLater(@NotNull Location location, @NotNull Runnable runnable, long delay) { + delay = Math.max(1, delay); + if (isFolia()) { + return scheduler.region(location).runDelayed((task) -> { + if (!runCatch(runnable, "Error in ensureLocationLater")) { + task.cancel(); + } + }, delay); + } else { + return Bukkit.getScheduler().runTaskLater(plugin, runnable, delay); + } + } + + /** + * Runs a task on the same thread as a location after a delay and repeats it until cancelled. + * On Spigot, this is the main thread. On Folia, this is the thread that the location is in. + * @param location The location to run the task on. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @param repeat The delay in ticks between each repeat of the task. + * @return The task object that can be used to cancel the task. Is a + * {@link FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object ensureLocationTimer(@NotNull Location location, @NotNull Runnable runnable, long delay, long repeat) { + delay = Math.max(1, delay); + repeat = Math.max(1, repeat); + if (isFolia()) { + + return scheduler.region(location).runAtFixedRate((task) -> { + if (!runCatch(runnable, "Error in ensureLocationTimer task")) + task.cancel(); + }, delay, repeat); + } else { + return Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, repeat); + } + } + + /** + * Runs a task asynchronously. + * @param runnable The task to run. + */ + public static void runAsync(@NotNull Runnable runnable) { + if (isFolia()) { + if (SHUTTING_DOWN.get()) { + runCatch(runnable, "Error in runAsync task on shutdown"); + return; + } + + scheduler.async().runNow((task) -> { + if (!runCatch(runnable, "Error in runAsync task")) { + task.cancel(); + } + }); + } else { + Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable); + } + } + + /** + * Runs a task asynchronously after a delay. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @return The task object that can be used to cancel the task. Is a + * {@link FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object runAsyncLater(@NotNull Runnable runnable, long delay) { + delay = Math.max(1, delay); + if (isFolia()) { + return scheduler.async().runDelayed((task) -> { + if (!runCatch(runnable, "Error in runAsyncLater task")) { + task.cancel(); + } + }, delay * 50, TimeUnit.MILLISECONDS); + } else { + return Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay); + } + } + + /** + * Runs a task asynchronously after a delay and repeats it until cancelled. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @param repeat The delay in ticks between each repeat of the task. + * @return The task object that can be used to cancel the task. Is a + * {@link FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object runAsyncTimer(@NotNull Runnable runnable, long delay, long repeat) { + delay = Math.max(1, delay); + if (isFolia()) { + return scheduler.async().runAtFixedRate((Consumer>) (task) -> runnable.run(), delay * 50, repeat * 50, TimeUnit.MILLISECONDS); + } else { + return Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, repeat); + } + } + + /** + * Runs a task synchronously. On Spigot, this is on the main thread. On Folia, + * this is on the global region thread.

+ * + * Warning: This should only be used for tasks that affect the world itself! Such as + * modifying gamerules, the weather, world time, etc. It should not be used for tasks + * that modify entities or the world, as those should be run using {@link #ensureEntity(Entity, Runnable)} + * or {@link #ensureLocation(Location, Runnable)}. + * + * @param runnable The task to run. + */ + public static void runGlobal(@NotNull Runnable runnable) { + if (isFolia()) { + if (SHUTTING_DOWN.get()) { + runCatch(runnable, "Error in runGlobal task on shutdown"); + return; + } + scheduler.global().run((task) -> { + if (!runCatch(runnable, "Error in runGlobal task")) { + task.cancel(); + } + }); + } else { + Bukkit.getScheduler().runTask(plugin, runnable); + } + } + + /** + * Runs a task synchronously after a delay. On Spigot, this is on the main thread. + * On Folia, this is on the global region thread.

+ * + * Warning: This should only be used for tasks that affect the world itself! Such as + * modifying gamerules, the weather, world time, etc. It should not be used for tasks + * that modify entities or the world, as those should be run using {@link #ensureEntityLater(Entity, Runnable, long)} + * or {@link #ensureLocationLater(Location, Runnable, long)}. + * + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @return The task object that can be used to cancel the task. Is a + * {@link FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object runGlobalLater(@NotNull Runnable runnable, long delay) { + delay = Math.max(1, delay); + if (isFolia()) { + return scheduler.global().runDelayed((task) -> { + if (!runCatch(runnable, "Error in runGlobalLater task")) { + task.cancel(); + } + }, delay); + } else { + return Bukkit.getScheduler().runTaskLater(plugin, runnable, delay); + } + } + + /** + * Runs a task synchronously after a delay and repeats it until cancelled. + * On Spigot, this is on the main thread. On Folia, this is on the global region thread.

+ * + * Warning: This should only be used for tasks that affect the world itself! Such as + * modifying gamerules, the weather, world time, etc. It should not be used for tasks + * that modify entities or the world, as those should be run using + * {@link #ensureEntityTimer(Entity, Runnable, long, long)} + * or {@link #ensureLocationTimer(Location, Runnable, long, long)} + * + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @param repeat The delay in ticks between each repeat of the task. + * @return The task object that can be used to cancel the task. Is a + * {@link FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object runGlobalTimer(@NotNull Runnable runnable, long delay, long repeat) { + delay = Math.max(1, delay); + if (isFolia()) { + return scheduler.global().runAtFixedRate((task) -> { + if (!runCatch(runnable, "Error in runGlobalTimer task")) { + task.cancel(); + } + }, delay, repeat); + } else { + return Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, repeat); + } + } + + /** + * Cancels a task that was created with either timers or delayed tasks. + * @param task The task to cancel. This is the object returned from + * {@link #ensureLocationTimer(Location, Runnable, long, long)} or + * {@link #ensureEntityTimer(Entity, Runnable, long, long)}. + * @return True if the task was cancelled successfully, false otherwise. + */ + public static boolean cancelTask(Object task) { + if (task == null) return false; + if (isFolia()) { + if (task instanceof FoliaTask) { + ((FoliaTask) task).cancel(); + return true; + } + } else { + if (task instanceof org.bukkit.scheduler.BukkitTask) { + ((org.bukkit.scheduler.BukkitTask) task).cancel(); + return true; + } + } + return false; + } + + /** + * Checks if a task is cancelled. + * @return True if the task is cancelled, false otherwise. + */ + public static boolean isTaskCancelled(Object task) { + if (task == null) return true; + if (isFolia()) { + if (task instanceof FoliaTask) { + return ((FoliaTask) task).isCancelled(); + } + } else { + if (task instanceof org.bukkit.scheduler.BukkitTask) { + return ((org.bukkit.scheduler.BukkitTask) task).isCancelled(); + } + } + return false; + } + + private static boolean runCatch(Runnable runnable, String error) { + try { + runnable.run(); + return true; + } catch (Exception e) { + JedCore.log.log(Level.WARNING, error, e); + return false; + } + } + + public static void shutdown() { + SHUTTING_DOWN.set(true); + } +} \ No newline at end of file diff --git a/src/com/jedk1/jedcore/util/ThrownEntityTracker.java b/src/com/jedk1/jedcore/util/ThrownEntityTracker.java index a2ac646..9d98376 100644 --- a/src/com/jedk1/jedcore/util/ThrownEntityTracker.java +++ b/src/com/jedk1/jedcore/util/ThrownEntityTracker.java @@ -4,7 +4,6 @@ import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.Ability; import com.projectkorra.projectkorra.util.DamageHandler; - import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; diff --git a/src/com/jedk1/jedcore/util/versionadapter/ParticleAdapter_1_20_4.java b/src/com/jedk1/jedcore/util/versionadapter/ParticleAdapter_1_20_4.java index 4d29090..d19b3f3 100644 --- a/src/com/jedk1/jedcore/util/versionadapter/ParticleAdapter_1_20_4.java +++ b/src/com/jedk1/jedcore/util/versionadapter/ParticleAdapter_1_20_4.java @@ -1,6 +1,7 @@ package com.jedk1.jedcore.util.versionadapter; -import org.bukkit.*; +import org.bukkit.Location; +import org.bukkit.Particle; public class ParticleAdapter_1_20_4 implements ParticleAdapter { diff --git a/src/com/jedk1/jedcore/util/versionadapter/ParticleAdapter_1_20_5.java b/src/com/jedk1/jedcore/util/versionadapter/ParticleAdapter_1_20_5.java index 0813924..6c43638 100644 --- a/src/com/jedk1/jedcore/util/versionadapter/ParticleAdapter_1_20_5.java +++ b/src/com/jedk1/jedcore/util/versionadapter/ParticleAdapter_1_20_5.java @@ -1,6 +1,8 @@ package com.jedk1.jedcore.util.versionadapter; -import org.bukkit.*; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; public class ParticleAdapter_1_20_5 implements ParticleAdapter { @@ -23,4 +25,4 @@ private int[] hexToRgb(String hex) { Integer.valueOf(hex.substring(5, 7), 16) }; } -} +} \ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml index 119cd14..5eb7f75 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -2,10 +2,14 @@ name: JedCore main: com.jedk1.jedcore.JedCore version: ${project.version} authors: ['jedk1'] -depend: ['ProjectKorra'] -api-version: 1.20 +depend: [ProjectKorra] +folia-supported: true +api-version: '1.20' +load: POSTWORLD +description: "A cool ProjectKorra addon plugin" + permissions: - #OP permissions + # OP permissions jedcore.admin: default: op description: Access to abilities and commands. @@ -25,18 +29,20 @@ permissions: bending.ability.ElementSphere.Stream: true bending.ability.Maelstrom: true bending.ability.SpiritBeam: true - #Player Permissions + + # Player Permissions jedcore.commands: default: true description: Access to player commands. children: bending.command.jedcore: true - bending.command.board: true + jedcore.passive: default: true description: Access to passive abilities. children: bending.ability.WallRun: true + jedcore.air: default: true description: Access to air abilities. @@ -48,17 +54,20 @@ permissions: bending.ability.Meditate: true bending.ability.SonicBlast: true bending.ability.AirSlam: true + jedcore.water: default: true description: Access to water abilities. children: bending.ability.FrostBreath: true bending.ability.IceClaws: true + bending.ability.IceSkate: true bending.ability.IceWall: true bending.ability.Drain: true bending.ability.WakeFishing: true bending.ability.WaterFlow: true bending.ability.WaterGimbal: true + jedcore.earth: default: true description: Access to earth abilities. @@ -78,6 +87,7 @@ permissions: bending.ability.MudSurge: true bending.ability.SandBlast: true bending.ability.MagmaBlast: true + jedcore.fire: default: true description: Access to fire abilities. @@ -90,9 +100,10 @@ permissions: bending.ability.FirePunch: true bending.ability.FireShots: true bending.ability.LightningBurst: true + jedcore.chi: default: true description: Access to chi abilities. children: bending.ability.Backstab: true - bending.ability.DaggerThrow: true \ No newline at end of file + bending.ability.DaggerThrow: true