diff --git a/src/com/projectkorra/ProjectKorra/BendingManager.java b/src/com/projectkorra/ProjectKorra/BendingManager.java index b1b7c16b..343dcc25 100644 --- a/src/com/projectkorra/ProjectKorra/BendingManager.java +++ b/src/com/projectkorra/ProjectKorra/BendingManager.java @@ -17,6 +17,7 @@ import com.projectkorra.ProjectKorra.airbending.AirBubble; import com.projectkorra.ProjectKorra.airbending.AirBurst; import com.projectkorra.ProjectKorra.airbending.AirPassive; import com.projectkorra.ProjectKorra.airbending.AirScooter; +import com.projectkorra.ProjectKorra.airbending.AirShield; import com.projectkorra.ProjectKorra.airbending.AirSpout; import com.projectkorra.ProjectKorra.airbending.Tornado; import com.projectkorra.ProjectKorra.chiblocking.ChiPassive; @@ -144,7 +145,11 @@ public class BendingManager implements Runnable { for (int ID : IceSpike.instances.keySet()) { IceSpike.instances.get(ID).progress(); } - + + for (int ID : AirShield.instances.keySet()) { + AirShield.progress(ID); + } + Shockwave.progressAll(); IceSpike2.progressAll(); diff --git a/src/com/projectkorra/ProjectKorra/ConfigManager.java b/src/com/projectkorra/ProjectKorra/ConfigManager.java index 1d5b8eaa..d7fa6ef2 100644 --- a/src/com/projectkorra/ProjectKorra/ConfigManager.java +++ b/src/com/projectkorra/ProjectKorra/ConfigManager.java @@ -105,6 +105,15 @@ public class ConfigManager { + "the general direction he's looking. Skilled airbenders can scale anything " + "with this ability."); + config.addDefault("Abilities.Air.AirShield.Enabled", true); + config.addDefault("Abilities.Air.AirShield.Description", "Air Shield is one of the most powerful defensive techniques in existence. " + + "To use, simply sneak (default: shift). " + + "This will create a whirlwind of air around the user, " + + "with a small pocket of safe space in the center. " + + "This wind will deflect all projectiles and will prevent any creature from " + + "entering it for as long as its maintained."); + config.addDefault("Abilities.Air.AirShield.Radius", 7); + config.addDefault("Abilities.Air.AirSpout.Enabled", true); config.addDefault("Abilities.Air.AirSpout.Description", "This ability gives the airbender limited sustained levitation. It is a " + "toggle - click to activate and form a whirling spout of air " diff --git a/src/com/projectkorra/ProjectKorra/PKListener.java b/src/com/projectkorra/ProjectKorra/PKListener.java index c969dd42..f5f458ef 100644 --- a/src/com/projectkorra/ProjectKorra/PKListener.java +++ b/src/com/projectkorra/ProjectKorra/PKListener.java @@ -47,6 +47,7 @@ import com.projectkorra.ProjectKorra.airbending.AirBlast; import com.projectkorra.ProjectKorra.airbending.AirBubble; import com.projectkorra.ProjectKorra.airbending.AirBurst; import com.projectkorra.ProjectKorra.airbending.AirScooter; +import com.projectkorra.ProjectKorra.airbending.AirShield; import com.projectkorra.ProjectKorra.airbending.AirSpout; import com.projectkorra.ProjectKorra.airbending.Tornado; import com.projectkorra.ProjectKorra.chiblocking.ChiPassive; @@ -164,6 +165,11 @@ public class PKListener implements Listener { } if (!player.isSneaking() && Methods.canBend(player.getName(), abil)) { + + if (abil.equalsIgnoreCase("AirShield")) { + new AirShield(player); + } + if (Methods.isAirAbility(abil)) { if (Methods.isWeapon(player.getItemInHand().getType()) && !plugin.getConfig().getBoolean("Properties.Air.CanBendWithWeapons")) { return; diff --git a/src/com/projectkorra/ProjectKorra/airbending/AirShield.java b/src/com/projectkorra/ProjectKorra/airbending/AirShield.java new file mode 100644 index 00000000..96973351 --- /dev/null +++ b/src/com/projectkorra/ProjectKorra/airbending/AirShield.java @@ -0,0 +1,165 @@ +package com.projectkorra.ProjectKorra.airbending; + +import java.util.HashMap; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import com.projectkorra.ProjectKorra.Methods; +import com.projectkorra.ProjectKorra.ProjectKorra; +import com.projectkorra.ProjectKorra.Ability.AvatarState; +import com.projectkorra.ProjectKorra.firebending.FireBlast; + +public class AirShield { + + public static ConcurrentHashMap instances = new ConcurrentHashMap(); + + private static double maxradius = ProjectKorra.plugin.getConfig().getDouble("Abilities.Air.AirShield.Radius"); + private static int numberOfStreams = (int) (.75 * (double) maxradius); + + private double radius = 2; + + private double speedfactor; + + private Player player; + private HashMap angles = new HashMap(); + + public AirShield(Player player) { + if (AvatarState.isAvatarState(player) + && instances.containsKey(player.getEntityId())) { + instances.remove(player.getEntityId()); + return; + } + this.player = player; + int angle = 0; + int di = (int) (maxradius * 2 / numberOfStreams); + for (int i = -(int) maxradius + di; i < (int) maxradius; i += di) { + angles.put(i, angle); + angle += 90; + if (angle == 360) + angle = 0; + } + + instances.put(player.getEntityId(), this); + } + + private void rotateShield() { + Location origin = player.getLocation(); + + FireBlast.removeFireBlastsAroundPoint(origin, radius); + + for (Entity entity : Methods.getEntitiesAroundPoint(origin, radius)) { +// if (Methods.isRegionProtectedFromBuild(player, Abilities.AirShield, +// entity.getLocation())) +// continue; + if (origin.distance(entity.getLocation()) > 2) { + double x, z, vx, vz, mag; + double angle = 50; + angle = Math.toRadians(angle); + + x = entity.getLocation().getX() - origin.getX(); + z = entity.getLocation().getZ() - origin.getZ(); + + mag = Math.sqrt(x * x + z * z); + + vx = (x * Math.cos(angle) - z * Math.sin(angle)) / mag; + vz = (x * Math.sin(angle) + z * Math.cos(angle)) / mag; + + Vector velocity = entity.getVelocity(); + if (AvatarState.isAvatarState(player)) { + velocity.setX(AvatarState.getValue(vx)); + velocity.setZ(AvatarState.getValue(vz)); + } else { + velocity.setX(vx); + velocity.setZ(vz); + } + + velocity.multiply(radius / maxradius); + entity.setVelocity(velocity); + entity.setFallDistance(0); + } + } + + Set keys = angles.keySet(); + for (int i : keys) { + double x, y, z; + double angle = (double) angles.get(i); + angle = Math.toRadians(angle); + + double factor = radius / maxradius; + + y = origin.getY() + factor * (double) i; + + //double theta = Math.asin(y/radius); + double f = Math.sqrt(1 - factor * factor * ((double) i / radius) + * ((double) i / radius)); + + x = origin.getX() + radius * Math.cos(angle) * f; + z = origin.getZ() + radius * Math.sin(angle) * f; + + Location effect = new Location(origin.getWorld(), x, y, z); + // if (!Methods.isRegionProtectedFromBuild(player, Abilities.AirShield, + // effect)) + origin.getWorld().playEffect(effect, Effect.SMOKE, 4, + (int) AirBlast.defaultrange); + + angles.put(i, angles.get(i) + (int) (10 * speedfactor)); + } + + if (radius < maxradius) { + radius += .3; + } + + if (radius > maxradius) + radius = maxradius; + + } + + public boolean progress() { + if (player.isDead() || !player.isOnline()) { + instances.remove(player.getEntityId()); + return false; + } +// if (Methods.isRegionProtectedFromBuild(player, Abilities.AirShield, +// player.getLocation())) { +// instances.remove(player.getEntityId()); +// return false; +// } + speedfactor = 1; + if (!Methods.canBend(player.getName(), "AirShield") + || player.getEyeLocation().getBlock().isLiquid()) { + instances.remove(player.getEntityId()); + return false; + } + + if (Methods.getBoundAbility(player) == null) { + instances.remove(player.getEntityId()); + return false; + } + if (((!Methods.getBoundAbility(player).equalsIgnoreCase("AirShield")) || (!player + .isSneaking())) && !AvatarState.isAvatarState(player)) { + instances.remove(player.getEntityId()); + return false; + } + rotateShield(); + return true; + } + + public static boolean progress(int ID) { + return instances.get(ID).progress(); + } + + public static String getDescription() { + return "Air Shield is one of the most powerful defensive techniques in existence. " + + "To use, simply sneak (default: shift). " + + "This will create a whirlwind of air around the user, " + + "with a small pocket of safe space in the center. " + + "This wind will deflect all projectiles and will prevent any creature from " + + "entering it for as long as its maintained. "; + } +} \ No newline at end of file diff --git a/src/config.yml b/src/config.yml index 3a453861..d8706d59 100644 --- a/src/config.yml +++ b/src/config.yml @@ -62,6 +62,10 @@ Abilities: Enabled: true Description: "AirScooter is a fast means of transportation. To use, sprint, jump then click with this ability selected. YOu will hop on a scooter of air and be propelled forward in the direction you're looking (you don't need to press anything). This ability can be used to levitate above liquids, but it cannot go up steep slopes. Any other actions will deactivate this ability." Speed: 0.675 + AirShield: + Enabled: true + Description: "Air Shield is one of the most powerful defensive techniques in existence. To use, simply sneak (default: shift). This will create a whirlwind of air around the user, with a small pocket of safe space in the center. This wind will deflect all projectiles and will prevent any creature from entering it for as long as its maintained." + Radius: 7 AirSpout: Enabled: true Description: "This ability gives the airbender limited sustained levitation. It is a toggle - click to activate and form a whirling spout of air beneath you, lifting you up. You can bend other abilities while using AirSpout. Click again to deactivate this ability."