diff --git a/src/com/projectkorra/ProjectKorra/BendingManager.java b/src/com/projectkorra/ProjectKorra/BendingManager.java index 54228d47..cf60a773 100644 --- a/src/com/projectkorra/ProjectKorra/BendingManager.java +++ b/src/com/projectkorra/ProjectKorra/BendingManager.java @@ -31,6 +31,8 @@ import com.projectkorra.ProjectKorra.firebending.FireStream; import com.projectkorra.ProjectKorra.firebending.Illumination; import com.projectkorra.ProjectKorra.waterbending.Bloodbending; import com.projectkorra.ProjectKorra.waterbending.FreezeMelt; +import com.projectkorra.ProjectKorra.waterbending.IceSpike; +import com.projectkorra.ProjectKorra.waterbending.IceSpike2; import com.projectkorra.ProjectKorra.waterbending.OctopusForm; import com.projectkorra.ProjectKorra.waterbending.Plantbending; import com.projectkorra.ProjectKorra.waterbending.Torrent; @@ -129,6 +131,12 @@ public class BendingManager implements Runnable { Wave.progress(ID); } + for (int ID : IceSpike.instances.keySet()) { + IceSpike.instances.get(ID).progress(); + } + + IceSpike2.progressAll(); + FireStream.dissipateAll(); } catch (Exception e) { Methods.stopBending(); diff --git a/src/com/projectkorra/ProjectKorra/BendingPlayer.java b/src/com/projectkorra/ProjectKorra/BendingPlayer.java index 15957fbe..db8feee4 100644 --- a/src/com/projectkorra/ProjectKorra/BendingPlayer.java +++ b/src/com/projectkorra/ProjectKorra/BendingPlayer.java @@ -17,6 +17,7 @@ public class BendingPlayer { HashMap abilities; boolean permaRemoved; boolean isToggled; + private long slowTime = 0; public BendingPlayer(UUID uuid, String player, ArrayList elements, HashMap abilities, boolean permaRemoved) { this.uuid = uuid; @@ -61,4 +62,12 @@ public class BendingPlayer { this.elements.clear(); this.elements.add(e); } + + public boolean canBeSlowed() { + return (System.currentTimeMillis() > slowTime); + } + + public void slow(long cooldown) { + slowTime = System.currentTimeMillis() + cooldown; + } } diff --git a/src/com/projectkorra/ProjectKorra/ConfigManager.java b/src/com/projectkorra/ProjectKorra/ConfigManager.java index 792de83e..a2924115 100644 --- a/src/com/projectkorra/ProjectKorra/ConfigManager.java +++ b/src/com/projectkorra/ProjectKorra/ConfigManager.java @@ -130,6 +130,19 @@ public class ConfigManager { config.addDefault("Abilities.Water.Bloodbending.ThrowFactor", 2); config.addDefault("Abilities.Water.Bloodbending.Range", 10); + config.addDefault("Abilities.Water.IceSpike.Enabled", true); + config.addDefault("Abilities.Water.IceSpike.Description", "This ability has many functions. Clicking while targetting ice, or an entity over some ice, " + + "will raise a spike of ice up, damaging and slowing the target. Tapping sneak (shift) while" + + " selecting a water source will select that source that can then be fired with a click. Firing" + + " this will launch a spike of ice at your target, dealing a bit of damage and slowing the target. " + + "If you sneak (shift) while not selecting a source, many ice spikes will erupt from around you, " + + "damaging and slowing those targets."); + config.addDefault("Abilities.Water.IceSpike.Cooldown", 2000); + config.addDefault("Abilities.Water.IceSpike.Damage", 2); + config.addDefault("Abilities.Water.IceSpike.Range", 20); + config.addDefault("Abilities.Water.IceSpike.ThrowingMult", 0.7); + config.addDefault("Abilities.Water.IceSpike.Height", 6); + config.addDefault("Abilities.Water.OctopusForm.Enabled", true); config.addDefault("Abilities.Water.OctopusForm.Description", "This ability allows the waterbender to manipulate a large quantity of water into a form resembling that of an octopus. " + "To use, click to select a water source. Then, hold sneak to channel this ability. " @@ -160,7 +173,7 @@ public class ConfigManager { config.addDefault("Abilities.Water.Torrent.Enabled", true); config.addDefault("Abilities.Water.Torrent.Description", "Torrent is one of the strongest moves in a waterbender's arsenal. To use, first click a source block to select it; then hold shift to begin streaming the water around you. Water flowing around you this way will damage and knock back nearby enemies and projectiles. If you release shift during this, you will create a large wave that expands outwards from you, launching anything in its path back. Instead, if you click you release the water and channel it to flow towards your cursor. Anything caught in the blast will be tossed about violently and take damage. Finally, if you click again when the water is torrenting, it will freeze the area around it when it is obstructed."); - + plugin.getConfig().addDefault("Abilities.Water.Plantbending.RegrowTime", 180000); config.addDefault("Abilities.Water.WaterBubble.Enabled", true); diff --git a/src/com/projectkorra/ProjectKorra/PKListener.java b/src/com/projectkorra/ProjectKorra/PKListener.java index 089cc456..1ba8cfc7 100644 --- a/src/com/projectkorra/ProjectKorra/PKListener.java +++ b/src/com/projectkorra/ProjectKorra/PKListener.java @@ -65,6 +65,7 @@ import com.projectkorra.ProjectKorra.firebending.FireStream; import com.projectkorra.ProjectKorra.firebending.Illumination; import com.projectkorra.ProjectKorra.waterbending.Bloodbending; import com.projectkorra.ProjectKorra.waterbending.FreezeMelt; +import com.projectkorra.ProjectKorra.waterbending.IceSpike2; import com.projectkorra.ProjectKorra.waterbending.Melt; import com.projectkorra.ProjectKorra.waterbending.OctopusForm; import com.projectkorra.ProjectKorra.waterbending.Torrent; @@ -181,6 +182,9 @@ public class PKListener implements Listener { if (abil.equalsIgnoreCase("Bloodbending")) { new Bloodbending(player); } + if (abil.equalsIgnoreCase("IceSpike")) { + new IceSpike2(player); + } if (abil.equalsIgnoreCase("OctopusForm")) { OctopusForm.form(player); } @@ -365,6 +369,9 @@ public class PKListener implements Listener { if (abil.equalsIgnoreCase("Bloodbending")) { Bloodbending.launch(player); } + if (abil.equalsIgnoreCase("IceSpike")) { + IceSpike2.activate(player); + } if (abil.equalsIgnoreCase("OctopusForm")) { new OctopusForm(player); } diff --git a/src/com/projectkorra/ProjectKorra/waterbending/IceSpike.java b/src/com/projectkorra/ProjectKorra/waterbending/IceSpike.java new file mode 100644 index 00000000..844fe8f7 --- /dev/null +++ b/src/com/projectkorra/ProjectKorra/waterbending/IceSpike.java @@ -0,0 +1,301 @@ +package com.projectkorra.ProjectKorra.waterbending; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; + +import com.projectkorra.ProjectKorra.BendingPlayer; +import com.projectkorra.ProjectKorra.Methods; +import com.projectkorra.ProjectKorra.ProjectKorra; +import com.projectkorra.ProjectKorra.TempPotionEffect; + +public class IceSpike { + + public static ConcurrentHashMap instances = new ConcurrentHashMap(); + public ConcurrentHashMap removeTimers = new ConcurrentHashMap(); + public static Map cooldowns = new HashMap(); + public static final int standardheight = ProjectKorra.plugin.getConfig().getInt("Abilities.Water.IceSpike.Height"); + public static long removeTimer = 500; + + private static ConcurrentHashMap alreadydoneblocks = new ConcurrentHashMap(); + private static ConcurrentHashMap baseblocks = new ConcurrentHashMap(); + + private static int ID = Integer.MIN_VALUE; + + private static double range = ProjectKorra.plugin.getConfig().getDouble("Abilities.Water.IceSpike.Range"); + public static long cooldown = ProjectKorra.plugin.getConfig().getLong("Abilities.Water.IceSpike.Cooldown"); + private static double speed = 25; + private static final Vector direction = new Vector(0, 1, 0); + + private static long interval = (long) (1000. / speed); + + private Location origin; + private Location location; + private Block block; + private Player player; + private int progress = 0; + private double damage = ProjectKorra.plugin.getConfig().getDouble("Abilities.Water.IceSpike.Damage"); + int id; + private long time; + int height = 2; + private Vector thrown = new Vector(0, ProjectKorra.plugin.getConfig().getDouble("Abilities.Water.IceSpike.ThrowingMult"), 0); + private ConcurrentHashMap affectedblocks = new ConcurrentHashMap(); + private List damaged = new ArrayList(); + + public IceSpike(Player player) { + if (cooldowns.containsKey(player)) + if (cooldowns.get(player) + cooldown >= System.currentTimeMillis()) + return; + try { + this.player = player; + + double lowestdistance = range + 1; + Entity closestentity = null; + for (Entity entity : Methods.getEntitiesAroundPoint( + player.getLocation(), range)) { + if (Methods.getDistanceFromLine(player.getLocation() + .getDirection(), player.getLocation(), entity + .getLocation()) <= 2 + && (entity instanceof LivingEntity) + && (entity.getEntityId() != player.getEntityId())) { + double distance = player.getLocation().distance( + entity.getLocation()); + if (distance < lowestdistance) { + closestentity = entity; + lowestdistance = distance; + } + } + } + if (closestentity != null) { + Block temptestingblock = closestentity.getLocation().getBlock() + .getRelative(BlockFace.DOWN, 1); + // if (temptestingblock.getType() == Material.ICE){ + this.block = temptestingblock; + // } + } else { + this.block = player.getTargetBlock(null, (int) range); + } + origin = block.getLocation(); + location = origin.clone(); + + } catch (IllegalStateException e) { + return; + } + + loadAffectedBlocks(); + + if (height != 0) { + if (canInstantiate()) { + id = ID; + instances.put(id, this); + if (ID >= Integer.MAX_VALUE) { + ID = Integer.MIN_VALUE; + } + ID++; + time = System.currentTimeMillis() - interval; + cooldowns.put(player.getName(), System.currentTimeMillis()); + } + } + } + + public IceSpike(Player player, Location origin, int damage, + Vector throwing, long aoecooldown) { + this.cooldown = aoecooldown; + this.player = player; + this.origin = origin; + location = origin.clone(); + block = location.getBlock(); + this.damage = damage; + this.thrown = throwing; + + loadAffectedBlocks(); + + if (block.getType() == Material.ICE) { + if (canInstantiate()) { + id = ID; + instances.put(id, this); + if (ID >= Integer.MAX_VALUE) { + ID = Integer.MIN_VALUE; + } + ID++; + time = System.currentTimeMillis() - interval; + } + } + } + + private void loadAffectedBlocks() { + affectedblocks.clear(); + Block thisblock; + for (int i = 1; i <= height; i++) { + thisblock = block.getWorld().getBlockAt( + location.clone().add(direction.clone().multiply(i))); + affectedblocks.put(thisblock, thisblock); + } + } + + private boolean blockInAffectedBlocks(Block block) { + if (affectedblocks.containsKey(block)) { + return true; + } + return false; + } + + public static boolean blockInAllAffectedBlocks(Block block) { + for (int ID : instances.keySet()) { + if (instances.get(ID).blockInAffectedBlocks(block)) + return true; + } + return false; + } + + public static void revertBlock(Block block) { + for (int ID : instances.keySet()) { + if (instances.get(ID).blockInAffectedBlocks(block)) { + instances.get(ID).affectedblocks.remove(block); + } + } + } + + private boolean canInstantiate() { + if (block.getType() != Material.ICE) + return false; + for (Block block : affectedblocks.keySet()) { + if (blockInAllAffectedBlocks(block) + || alreadydoneblocks.containsKey(block) + || block.getType() != Material.AIR + || (block.getX() == player.getEyeLocation().getBlock() + .getX() && block.getZ() == player.getEyeLocation() + .getBlock().getZ())) { + return false; + } + } + return true; + } + + public boolean progress() { + if (System.currentTimeMillis() - time >= interval) { + time = System.currentTimeMillis(); + if (progress < height) { + moveEarth(); + removeTimers.put(player, System.currentTimeMillis()); + } else { + if (removeTimers.get(player) + removeTimer <= System + .currentTimeMillis()) { + baseblocks.put( + location.clone() + .add(direction.clone().multiply( + -1 * (height))).getBlock(), + (height - 1)); + if (!revertblocks()) { + instances.remove(id); + } + } + + return false; + } + } + return true; + } + + private boolean moveEarth() { + progress++; + Block affectedblock = location.clone().add(direction).getBlock(); + location = location.add(direction); +// if (Methods.isRegionProtectedFromBuild(player, Abilities.IceSpike, +// location)) +// return false; + for (Entity en : Methods.getEntitiesAroundPoint(location, 1.4)) { + if (en instanceof LivingEntity && en != player + && !damaged.contains(((LivingEntity) en))) { + LivingEntity le = (LivingEntity) en; + affect(le); + // le.setVelocity(thrown); + // le.damage(damage); + // damaged.add(le); + // Methods.verbose(damage + " Hp:" + le.getHealth()); + } + } + affectedblock.setType(Material.ICE); + loadAffectedBlocks(); + + if (location.distance(origin) >= height) { + return false; + } + + return true; + } + + private void affect(LivingEntity entity) { + entity.setVelocity(thrown); + entity.damage(damage); + damaged.add(entity); + long slowCooldown = IceSpike2.slowCooldown; + int mod = 2; + if (entity instanceof Player) { + BendingPlayer bPlayer = Methods.getBendingPlayer(player.getName()); + if (bPlayer.canBeSlowed()) { + PotionEffect effect = new PotionEffect(PotionEffectType.SLOW, + 70, mod); + new TempPotionEffect(entity, effect); + bPlayer.slow(slowCooldown); + } + } else { + PotionEffect effect = new PotionEffect(PotionEffectType.SLOW, 70, + mod); + new TempPotionEffect(entity, effect); + } + + } + + public static boolean blockIsBase(Block block) { + if (baseblocks.containsKey(block)) { + return true; + } + return false; + } + + public static void removeBlockBase(Block block) { + if (baseblocks.containsKey(block)) { + baseblocks.remove(block); + } + + } + + public static void removeAll() { + for (int ID : instances.keySet()) { + instances.remove(ID); + } + } + + public boolean revertblocks() { + Vector direction = new Vector(0, -1, 0); + location.getBlock().setType(Material.AIR);// .clone().add(direction).getBlock().setType(Material.AIR); + location.add(direction); + if (blockIsBase(location.getBlock())) + return false; + return true; + } + + public static String getDescription() { + return "This ability has many functions. Clicking while targetting ice, or an entity over some ice, " + + "will raise a spike of ice up, damaging and slowing the target. Tapping sneak (shift) while" + + " selecting a water source will select that source that can then be fired with a click. Firing" + + " this will launch a spike of ice at your target, dealing a bit of damage and slowing the target. " + + "If you sneak (shift) while not selecting a source, many ice spikes will erupt from around you, " + + "damaging and slowing those targets."; + } + +} \ No newline at end of file diff --git a/src/com/projectkorra/ProjectKorra/waterbending/IceSpike2.java b/src/com/projectkorra/ProjectKorra/waterbending/IceSpike2.java new file mode 100644 index 00000000..2775f96f --- /dev/null +++ b/src/com/projectkorra/ProjectKorra/waterbending/IceSpike2.java @@ -0,0 +1,447 @@ +package com.projectkorra.ProjectKorra.waterbending; + +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; + +import com.projectkorra.ProjectKorra.BendingPlayer; +import com.projectkorra.ProjectKorra.Methods; +import com.projectkorra.ProjectKorra.TempBlock; +import com.projectkorra.ProjectKorra.TempPotionEffect; + +public class IceSpike2 { + + private static ConcurrentHashMap instances = new ConcurrentHashMap(); + + private static double defaultrange = 20; + private static int defaultdamage = 1; + private static int defaultmod = 2; + private static int ID = Integer.MIN_VALUE; + static long slowCooldown = 5000; + + private static final long interval = 20; + private static final byte data = 0; + private static final double affectingradius = 2; + private static final double deflectrange = 3; + + private Player player; + private int id; + private double range; + private boolean plantbending = false; + private Block sourceblock; + private TempBlock source; + private boolean prepared = false; + private boolean settingup = false; + private boolean progressing = false; + private long time; + + private Location location; + private Location firstdestination; + private Location destination; + + public IceSpike2(Player player) { + block(player); + if (Methods.canPlantbend(player)) + plantbending = true; + range = Methods.waterbendingNightAugment(defaultrange, player.getWorld()); + this.player = player; + Block sourceblock = Methods.getWaterSourceBlock(player, range, + plantbending); + + if (sourceblock == null) { + new SpikeField(player); + } else { + prepare(sourceblock); + } + + } + + private void prepare(Block block) { + for (IceSpike2 ice : getInstances(player)) { + if (ice.prepared) { + ice.cancel(); + } + } + sourceblock = block; + location = sourceblock.getLocation(); + prepared = true; + createInstance(); + } + + private void createInstance() { + id = ID++; + instances.put(id, this); + if (ID >= Integer.MAX_VALUE) { + ID = Integer.MIN_VALUE; + } + } + + private static ArrayList getInstances(Player player) { + ArrayList list = new ArrayList(); + for (int id : instances.keySet()) { + IceSpike2 ice = instances.get(id); + if (ice.player.equals(player)) { + list.add(ice); + } + } + + return list; + } + + public static void activate(Player player) { + redirect(player); + boolean activate = false; + + if (IceSpike.cooldowns.containsKey(player.getName())) { + if (IceSpike.cooldowns.get(player.getName()) + IceSpike.cooldown >= System.currentTimeMillis()) { + return; + } else { + IceSpike.cooldowns.remove(player.getName()); + } + } + + for (IceSpike2 ice : getInstances(player)) { + if (ice.prepared) { + ice.throwIce(); + activate = true; + } + } + + if (!activate) { + IceSpike spike = new IceSpike(player); + if (spike.id == 0) { + waterBottle(player); + } + } + } + + private static void waterBottle(Player player) { + if (WaterReturn.hasWaterBottle(player)) { + Location eyeloc = player.getEyeLocation(); + Block block = eyeloc.add(eyeloc.getDirection().normalize()) + .getBlock(); + if (Methods.isTransparentToEarthbending(player, block) + && Methods.isTransparentToEarthbending(player, + eyeloc.getBlock())) { + + LivingEntity target = (LivingEntity) Methods.getTargetedEntity( + player, defaultrange, new ArrayList()); + Location destination; + if (target == null) { + destination = Methods.getTargetedLocation(player, + defaultrange, Methods.transparentToEarthbending); + } else { + destination = Methods.getPointOnLine(player.getEyeLocation(), + target.getEyeLocation(), defaultrange); + } + + if (destination.distance(block.getLocation()) < 1) + return; + + block.setType(Material.WATER); + block.setData((byte) 0x0); + IceSpike2 ice = new IceSpike2(player); + ice.throwIce(); + + if (ice.progressing) { + WaterReturn.emptyWaterBottle(player); + } else { + block.setType(Material.AIR); + } + + } + } + } + + private void throwIce() { + if (!prepared) + return; + LivingEntity target = (LivingEntity) Methods.getTargetedEntity(player, + range, new ArrayList()); + if (target == null) { + destination = Methods.getTargetedLocation(player, range, + Methods.transparentToEarthbending); + } else { + destination = target.getEyeLocation(); + } + + location = sourceblock.getLocation(); + if (destination.distance(location) < 1) + return; + firstdestination = location.clone(); + if (destination.getY() - location.getY() > 2) { + firstdestination.setY(destination.getY() - 1); + } else { + firstdestination.add(0, 2, 0); + } + destination = Methods + .getPointOnLine(firstdestination, destination, range); + progressing = true; + settingup = true; + prepared = false; + + if (Methods.isPlant(sourceblock)) { + new Plantbending(sourceblock); + sourceblock.setType(Material.AIR); + } else if (!Methods.isAdjacentToThreeOrMoreSources(sourceblock)) { + sourceblock.setType(Material.AIR); + } + + source = new TempBlock(sourceblock, Material.ICE, data); + } + + public static void progressAll() { + for (int id : instances.keySet()) { + instances.get(id).progress(); + } + } + + private void progress() { + if (player.isDead() || !player.isOnline() + || !Methods.canBend(player.getName(), "IceSpike")) { + cancel(); + return; + } + + if (!player.getWorld().equals(location.getWorld())) { + cancel(); + return; + } + + if (player.getEyeLocation().distance(location) >= range) { + if (progressing) { + cancel(); + returnWater(); + } else { + cancel(); + } + return; + } + + if ((Methods.getBoundAbility(player) == null || !Methods.getBoundAbility(player).equalsIgnoreCase("IceSpike")) && prepared) { + cancel(); + return; + } + + if (System.currentTimeMillis() < time + interval) + return; + + time = System.currentTimeMillis(); + + if (progressing) { + + Vector direction; + + if (location.getBlockY() == firstdestination.getBlockY()) + settingup = false; + + if (location.distance(destination) <= 2) { + cancel(); + returnWater(); + return; + } + + if (settingup) { + direction = Methods.getDirection(location, firstdestination) + .normalize(); + } else { + direction = Methods.getDirection(location, destination) + .normalize(); + } + + location.add(direction); + + Block block = location.getBlock(); + + if (block.equals(sourceblock)) + return; + + source.revertBlock(); + source = null; + + if (Methods.isTransparentToEarthbending(player, block) + && !block.isLiquid()) { + Methods.breakBlock(block); + } else if (!Methods.isWater(block)) { + cancel(); + returnWater(); + return; + } + +// if (Methods.isRegionProtectedFromBuild(player, Abilities.IceSpike, +// location)) { +// cancel(); +// returnWater(); +// return; +// } + + for (Entity entity : Methods.getEntitiesAroundPoint(location, + affectingradius)) { + if (entity.getEntityId() != player.getEntityId() + && entity instanceof LivingEntity) { + affect((LivingEntity) entity); + progressing = false; + returnWater(); + } + } + + if (!progressing) { + cancel(); + return; + } + + sourceblock = block; + source = new TempBlock(sourceblock, Material.ICE, data); + + } else if (prepared) { + Methods.playFocusWaterEffect(sourceblock); + } + } + + private void affect(LivingEntity entity) { + int mod = (int) Methods.waterbendingNightAugment(defaultmod, + player.getWorld()); + int damage = (int) Methods.waterbendingNightAugment(defaultdamage, + player.getWorld()); + if (entity instanceof Player) { + BendingPlayer bPlayer = Methods.getBendingPlayer(player.getName()); + if (bPlayer.canBeSlowed()) { + PotionEffect effect = new PotionEffect(PotionEffectType.SLOW, + 70, mod); + new TempPotionEffect(entity, effect); + bPlayer.slow(slowCooldown); + entity.damage(damage, player); + } + } else { + PotionEffect effect = new PotionEffect(PotionEffectType.SLOW, 70, + mod); + new TempPotionEffect(entity, effect); + entity.damage(damage, player); + } + + } + + private static void redirect(Player player) { + + for (int id : instances.keySet()) { + IceSpike2 ice = instances.get(id); + + if (!ice.progressing) + continue; + + if (!ice.location.getWorld().equals(player.getWorld())) + continue; + + if (ice.player.equals(player)) { + Location location; + Entity target = Methods.getTargetedEntity(player, defaultrange, new ArrayList()); + if (target == null) { + location = Methods.getTargetedLocation(player, defaultrange); + } else { + location = ((LivingEntity) target).getEyeLocation(); + } + location = Methods.getPointOnLine(ice.location, location, + defaultrange * 2); + ice.redirect(location, player); + } + + Location location = player.getEyeLocation(); + Vector vector = location.getDirection(); + Location mloc = ice.location; +// if (Methods.isRegionProtectedFromBuild(player, Abilities.IceSpike, +// mloc)) +// continue; + if (mloc.distance(location) <= defaultrange + && Methods.getDistanceFromLine(vector, location, ice.location) < deflectrange + && mloc.distance(location.clone().add(vector)) < mloc + .distance(location.clone().add( + vector.clone().multiply(-1)))) { + Location loc; + Entity target = Methods.getTargetedEntity(player, defaultrange, new ArrayList()); + if (target == null) { + loc = Methods.getTargetedLocation(player, defaultrange); + } else { + loc = ((LivingEntity) target).getEyeLocation(); + } + loc = Methods.getPointOnLine(ice.location, loc, defaultrange * 2); + ice.redirect(loc, player); + } + + } + } + + private static void block(Player player) { + for (int id : instances.keySet()) { + IceSpike2 ice = instances.get(id); + + if (ice.player.equals(player)) + continue; + + if (!ice.location.getWorld().equals(player.getWorld())) + continue; + + if (!ice.progressing) + continue; + +// if (Methods.isRegionProtectedFromBuild(player, Abilities.IceSpike, +// ice.location)) +// continue; + + Location location = player.getEyeLocation(); + Vector vector = location.getDirection(); + Location mloc = ice.location; + if (mloc.distance(location) <= defaultrange + && Methods.getDistanceFromLine(vector, location, ice.location) < deflectrange + && mloc.distance(location.clone().add(vector)) < mloc + .distance(location.clone().add( + vector.clone().multiply(-1)))) { + ice.cancel(); + } + + } + } + + private void redirect(Location destination, Player player) { + this.destination = destination; + this.player = player; + } + + private void cancel() { + if (progressing) { + if (source != null) + source.revertBlock(); + progressing = false; + } + + instances.remove(id); + } + + private void returnWater() { + new WaterReturn(player, sourceblock); + } + + public static void removeAll() { + for (int id : instances.keySet()) { + instances.get(id).cancel(); + } + + instances.clear(); + } + + public static boolean isBending(Player player) { + for (int id : instances.keySet()) { + if (instances.get(id).player.equals(player)) + return true; + } + return false; + } +} \ No newline at end of file diff --git a/src/com/projectkorra/ProjectKorra/waterbending/SpikeField.java b/src/com/projectkorra/ProjectKorra/waterbending/SpikeField.java new file mode 100644 index 00000000..37e8e000 --- /dev/null +++ b/src/com/projectkorra/ProjectKorra/waterbending/SpikeField.java @@ -0,0 +1,139 @@ +package com.projectkorra.ProjectKorra.waterbending; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import com.projectkorra.ProjectKorra.Methods; +import com.projectkorra.ProjectKorra.ProjectKorra; + +public class SpikeField { + + private static int radius = 6; + public static int numofspikes = ((radius * 2) * (radius * 2)) / 16; + private static long cooldown = ProjectKorra.plugin.getConfig().getLong("Abilities.Water.IceSpike.Cooldown"); + public static Map cooldowns = new HashMap(); + + Random ran = new Random(); + private int damage = 2; + private Vector thrown = new Vector(0, 1, 0); + + public SpikeField(Player p) { + if (cooldowns.containsKey(p)) + if (cooldowns.get(p) + cooldown >= System.currentTimeMillis()) + return; + // Tools.verbose("Trying to create IceField" + numofspikes); + int locX = p.getLocation().getBlockX(); + int locY = p.getLocation().getBlockY(); + int locZ = p.getLocation().getBlockZ(); + List iceblocks = new ArrayList(); + for (int x = -(radius - 1); x <= (radius - 1); x++) { + for (int z = -(radius - 1); z <= (radius - 1); z++) { + for (int y = -1; y <= 1; y++) { + Block testblock = p.getWorld().getBlockAt(locX + x, + locY + y, locZ + z); + if (testblock.getType() == Material.ICE + && testblock.getRelative(BlockFace.UP).getType() == Material.AIR + && !(testblock.getX() == p.getEyeLocation() + .getBlock().getX() && testblock.getZ() == p + .getEyeLocation().getBlock().getZ())) { + iceblocks.add(testblock); + // /Tools.verbose("X: " + testblock.getLocation().getX() + // + " Y: " + testblock.getLocation().getY() + " Z: " + + // testblock.getLocation().getZ()); + } + } + } + } + + List entities = Methods.getEntitiesAroundPoint(p.getLocation(), + radius); + + for (int i = 0; i < numofspikes; i++) { + if (iceblocks.isEmpty()) + return; + + Entity target = null; + Block targetblock = null; + for (Entity entity : entities) { + if (entity instanceof LivingEntity + && entity.getEntityId() != p.getEntityId()) { + for (Block block : iceblocks) { + if (block.getX() == entity.getLocation().getBlockX() + && block.getZ() == entity.getLocation() + .getBlockZ()) { + target = entity; + targetblock = block; + break; + } + } + } else { + continue; + } + } + + if (target != null) { + entities.remove(target); + } else { + targetblock = iceblocks.get(ran.nextInt(iceblocks.size())); + } + + // Tools.verbose("X: " + targetblock.getLocation().getX() + " Y: " + + // targetblock.getLocation().getY() + " Z: " + + // targetblock.getLocation().getZ()); + if (targetblock.getRelative(BlockFace.UP).getType() != Material.ICE) { + new IceSpike(p, targetblock.getLocation(), damage, thrown, cooldown); + IceSpike.cooldowns.put(p.getName(), System.currentTimeMillis()); + iceblocks.remove(targetblock); + } + } + } +} +// for (int i = 0; i < (numofspikes / 2); i++){ +// int blockX = ran.nextInt(radius) + 1; +// int blockZ = ran.nextInt((radius * 2) + 1) - radius; +// Block b = p.getLocation().getWorld().getBlockAt(locX + blockX, locY - 1, locZ +// - blockZ); +// if (b.getType() == Material.ICE){ +// new IceSpike(p, b.getLocation(), 2); +// } else { +// for (i = 0; i <= heigth; i++) { +// b = b.getRelative(BlockFace.DOWN); +// if (b.getType() == Material.ICE){ +// new IceSpike(p, b.getLocation(), 2); +// break; +// } +// } +// } +// +// } +// for (int i = 0; i < (numofspikes / 2); i++){ +// int blockX = ran.nextInt(radius) + 1; +// int blockZ = ran.nextInt((radius * 2) + 1) - radius; +// Block b = p.getLocation().getWorld().getBlockAt(locX - blockX, locY - 1, locZ +// - blockZ); +// if (b.getType() == Material.ICE) { +// new IceSpike(p, b.getLocation(), 2); +// } else { +// for (i = 0; i <= heigth; i++) { +// b = b.getRelative(BlockFace.DOWN); +// if (b.getType() == Material.ICE){ +// new IceSpike(p, b.getLocation(), 2); +// break; +// } +// } +// } +// } +// } +// } \ No newline at end of file diff --git a/src/config.yml b/src/config.yml index 58449a7b..d7e7e034 100644 --- a/src/config.yml +++ b/src/config.yml @@ -82,6 +82,14 @@ Abilities: Description: "This ability was made illegal for a reason. With this ability selected, sneak while targeting something and you will bloodbend that target. Bloodbent targets cannot move, bend, or attack. You are free to control their actions by looking elsewhere - they will be forced to move in that direciton. Additionally, clicking while bloodbending will launch that target off in the direction you're looking. People who are capable of bloodbending are immune to technique, and you are immune to theirs."; ThrowFactor: 2 Range: 10 + IceSpike: + Enabled: true + Description: "This ability has many functions. Clicking while targetting ice, or an entity over some ice, will raise a spike of ice up, damaging and slowing the target. Tapping sneak (default: shift) while selecting a water source will select that source that can be fired with a click. Firing this will launch a spike of ice at your target, dealing a bit of damage and slowing the target. If you sneak (shift) will not selecting a source, many ice spikes will erupt from around you, damaging and slowing those targets." + Cooldown: 2000 + Damage: 2 + Range: 20 + ThrowingMult: 0.7 + Height: 6 OctopusForm: Enabled: true Description: "This ability allows the waterbender to manipulate a large quantity of water into a form resembling that of an octopus. To use, click to select a water source. Then, hold sneak to channel this ability. While channleing, the water will form itself around you and has a chance to block incoming attacks. Additionally, you can click while channeling to attack things near you, dealing damage and knocking the target back. Releasing shift at any time will dissipate the form."