New Ability: Suffocate

This commit is contained in:
nathank33 2015-01-31 21:37:28 -08:00
parent 85c9c86743
commit 1da91706da
4 changed files with 675 additions and 179 deletions

View file

@ -223,9 +223,24 @@ public class ConfigManager {
config.addDefault("Abilities.Air.Suffocate.Enabled", true); config.addDefault("Abilities.Air.Suffocate.Enabled", true);
config.addDefault("Abilities.Air.Suffocate.Description", "This ability is one of the most dangerous abilities an Airbender possesses. To use, simply look at an entity and hold shift. The entity will begin taking damage as you extract the air from their lungs. Any bender caught in this sphere will only be able to use basic moves, such as AirSwipe, WaterManipulation, FireBlast, or EarthBlast. An entity can be knocked out of the sphere by certain bending arts, and your attention will be disrupted if you are hit by bending."); config.addDefault("Abilities.Air.Suffocate.Description", "This ability is one of the most dangerous abilities an Airbender possesses. To use, simply look at an entity and hold shift. The entity will begin taking damage as you extract the air from their lungs. Any bender caught in this sphere will only be able to use basic moves, such as AirSwipe, WaterManipulation, FireBlast, or EarthBlast. An entity can be knocked out of the sphere by certain bending arts, and your attention will be disrupted if you are hit by bending.");
config.addDefault("Abilities.Air.Suffocate.ChargeTime", 1000);
config.addDefault("Abilities.Air.Suffocate.Cooldown", 0);
config.addDefault("Abilities.Air.Suffocate.Range", 15);
config.addDefault("Abilities.Air.Suffocate.Damage", 2);
config.addDefault("Abilities.Air.Suffocate.DamageInitialDelay", 2);
config.addDefault("Abilities.Air.Suffocate.DamageInterval", 1);
config.addDefault("Abilities.Air.Suffocate.SlowPotency", 1);
config.addDefault("Abilities.Air.Suffocate.SlowDelay", 0.5);
config.addDefault("Abilities.Air.Suffocate.SlowInterval", 1.25);
config.addDefault("Abilities.Air.Suffocate.BlindPotentcy", 30);
config.addDefault("Abilities.Air.Suffocate.BlindDelay", 2);
config.addDefault("Abilities.Air.Suffocate.BlindInterval", 1.5);
config.addDefault("Abilities.Air.Suffocate.CanBeUsedOnUndeadMobs", true); config.addDefault("Abilities.Air.Suffocate.CanBeUsedOnUndeadMobs", true);
config.addDefault("Abilities.Air.Suffocate.Range", 5); config.addDefault("Abilities.Air.Suffocate.RequireConstantAim", true);
config.addDefault("Abilities.Air.Suffocate.Damage", 0.5); config.addDefault("Abilities.Air.Suffocate.RequireConstantAimRadius", 5);
config.addDefault("Abilities.Air.Suffocate.AnimationRadius", 2.0);
config.addDefault("Abilities.Air.Suffocate.AnimationParticleAmount", 2);
config.addDefault("Abilities.Air.Suffocate.AnimationSpeed", 1.0);
config.addDefault("Abilities.Air.Tornado.Radius", 10); config.addDefault("Abilities.Air.Tornado.Radius", 10);
config.addDefault("Abilities.Air.Tornado.Height", 25); config.addDefault("Abilities.Air.Tornado.Height", 25);

View file

@ -1232,6 +1232,10 @@ public class PKListener implements Listener {
return; return;
} }
if(entity instanceof Player) {
Suffocate.remove((Player) entity);
}
Entity en = e.getEntity(); Entity en = e.getEntity();
if (en instanceof Player) { if (en instanceof Player) {
// Player p = (Player) en; // This is the player getting hurt. // Player p = (Player) en; // This is the player getting hurt.

View file

@ -1,220 +1,682 @@
package com.projectkorra.ProjectKorra.airbending; package com.projectkorra.ProjectKorra.airbending;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.ConcurrentModificationException; import java.util.Enumeration;
import java.util.HashMap; import java.util.Iterator;
import java.util.Map; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Creature; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector; import org.bukkit.scheduler.BukkitRunnable;
import com.projectkorra.ProjectKorra.Commands; import com.projectkorra.ProjectKorra.BendingPlayer;
import com.projectkorra.ProjectKorra.Methods; import com.projectkorra.ProjectKorra.Methods;
import com.projectkorra.ProjectKorra.ProjectKorra; import com.projectkorra.ProjectKorra.ProjectKorra;
import com.projectkorra.ProjectKorra.TempPotionEffect;
import com.projectkorra.ProjectKorra.Ability.AvatarState; import com.projectkorra.ProjectKorra.Ability.AvatarState;
import com.projectkorra.ProjectKorra.Utilities.ParticleEffect;
/**
* Suffocate
*
* Suffocate is an air ability that causes entities to be surrounded by
* a sphere air that causes constant damage after a configurable delay.
* Suffocate also causes Blinding and Slowing affects to entities depending
* on how the ability is configured. While in AvatarState this ability can
* be used on multiple entities within a large radius.
* If the user is damaged while performing this ability then the ability is removed.
*/
public class Suffocate { public class Suffocate {
public static enum SpiralType {
HORIZONTAL1, HORIZONTAL2, VERTICAL1, VERTICAL2, DIAGONAL1, DIAGONAL2
};
public static ConcurrentHashMap<Player, Suffocate> instances = new ConcurrentHashMap<Player, Suffocate>(); private static ConcurrentHashMap<Player, Suffocate> instances = new ConcurrentHashMap<Player, Suffocate>();
private static boolean canBeUsedOnUndead = ProjectKorra.plugin.getConfig().getBoolean("Abilities.Air.Suffocate.CanBeUsedOnUndeadMobs"); private static FileConfiguration config = ProjectKorra.plugin.getConfig();
private int range = ProjectKorra.plugin.getConfig().getInt("Abilities.Air.Suffocate.Range"); private static final boolean CAN_SUFFOCATE_UNDEAD = config.getBoolean("Abilities.Air.Suffocate.CanBeUsedOnUndeadMobs");
private double damage = ProjectKorra.plugin.getConfig().getDouble("Abilities.Air.Suffocate.Damage"); private static final boolean REQUIRE_CONSTANT_AIM = config.getBoolean("Abilities.Air.Suffocate.RequireConstantAim");
private static final double ANIM_RADIUS = config.getDouble("Abilities.Air.Suffocate.AnimationRadius");
private static final int ANIM_PARTICLE_AMOUNT = config.getInt("Abilities.Air.Suffocate.AnimationParticleAmount");
private static final double ANIM_SPEED = config.getDouble("Abilities.Air.Suffocate.AnimationSpeed");
private static final long CHARGE_TIME = config.getLong("Abilities.Air.Suffocate.ChargeTime");
private static final long COOLDOWN = config.getLong("Abilities.Air.Suffocate.Cooldown");
private static final double RANGE = config.getDouble("Abilities.Air.Suffocate.Range");
private static double AIM_RADIUS = config.getDouble("Abilities.Air.Suffocate.RequireConstantAimRadius");
private static double DAMAGE = config.getDouble("Abilities.Air.Suffocate.Damage");
private static double DAMAGE_INITIAL_DELAY = config.getDouble("Abilities.Air.Suffocate.DamageInitialDelay");
private static double DAMAGE_INTERVAL = config.getDouble("Abilities.Air.Suffocate.DamageInterval");
private static int SLOW = config.getInt("Abilities.Air.Suffocate.SlowPotency");
private static double SLOW_INTERVAL = config.getDouble("Abilities.Air.Suffocate.SlowInterval");
private static double SLOW_DELAY = config.getDouble("Abilities.Air.Suffocate.SlowDelay");
private static int BLIND = config.getInt("Abilities.Air.Suffocate.BlindPotentcy");
private static double BLIND_DELAY = config.getDouble("Abilities.Air.Suffocate.BlindDelay");
private static double BLIND_INTERVAL = config.getDouble("Abilities.Air.Suffocate.BlindInterval");
private Map<Entity, Location> targets = new HashMap<Entity, Location>();
private Player player; private Player player;
private BendingPlayer bplayer;
private boolean started = false;
private long time; private long time;
private long warmup = 2000; private ArrayList<BukkitRunnable> tasks;
private ArrayList<LivingEntity> targets;
private PotionEffect slow = new PotionEffect(PotionEffectType.SLOW, 60, 1); private boolean reqConstantAim;
private PotionEffect nausea = new PotionEffect(PotionEffectType.SLOW, 60, 1); private boolean canSuffUndead;
private long chargeTime, cooldown;
private int particleScale;
private double range, radius;
private double speedFactor;
private double aimRadius;
private double damage, damageDelay, damageRepeat;
private double slow, slowRepeat, slowDelay;
private double blind, blindDelay, blindRepeat;
public Suffocate(Player player) { public Suffocate(Player player) {
if (instances.containsKey(player)) {
remove(player);
return;
}
if (AvatarState.isAvatarState(player)) {
range = AvatarState.getValue(range);
for (Entity entity: Methods.getEntitiesAroundPoint(player.getLocation(), range)) {
if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId()) {
targets.put(entity, entity.getLocation());
}
}
} else {
Entity en = Methods.getTargetedEntity(player, range, new ArrayList<Entity>());
if (en != null && en instanceof LivingEntity && en.getEntityId() != player.getEntityId()) {
targets.put(en, en.getLocation());
}
}
this.player = player; this.player = player;
instances.put(player, this); bplayer = Methods.getBendingPlayer(player.getName());
targets = new ArrayList<LivingEntity>();
tasks = new ArrayList<BukkitRunnable>();
time = System.currentTimeMillis(); time = System.currentTimeMillis();
}
private void progress() { reqConstantAim = REQUIRE_CONSTANT_AIM;
if (!player.isSneaking()) { canSuffUndead = CAN_SUFFOCATE_UNDEAD;
remove(player); chargeTime = CHARGE_TIME;
cooldown = COOLDOWN;
particleScale = ANIM_PARTICLE_AMOUNT;
range = RANGE;
radius = ANIM_RADIUS;
speedFactor = ANIM_SPEED;
aimRadius = AIM_RADIUS;
damage = DAMAGE;
damageDelay = DAMAGE_INITIAL_DELAY;
damageRepeat = DAMAGE_INTERVAL;
slow = SLOW;
slowRepeat = SLOW_INTERVAL;
slowDelay = SLOW_DELAY;
blind = BLIND;
blindDelay = BLIND_DELAY;
blindRepeat = BLIND_INTERVAL;
if(instances.containsKey(player))
return; return;
if(AvatarState.isAvatarState(player)) {
cooldown = 0;
chargeTime = 0;
reqConstantAim = false;
damage = AvatarState.getValue(damage);
range *= 2;
slow = AvatarState.getValue(slow);
slowRepeat = AvatarState.getValue(slowRepeat);
blind = AvatarState.getValue(blind);
blindRepeat = AvatarState.getValue(blindRepeat);
}
if(particleScale < 1)
particleScale = 1;
else if(particleScale > 2)
particleScale = 2;
if(AvatarState.isAvatarState(player)) {
for(Entity ent : Methods.getEntitiesAroundPoint(player.getLocation(), range))
if(ent instanceof LivingEntity && !ent.equals(player))
targets.add((LivingEntity) ent);
}
else {
Entity ent = Methods.getTargetedEntity(player, range, new ArrayList<Entity>());
if(ent != null && ent instanceof LivingEntity)
targets.add((LivingEntity) ent);
} }
if (player.isDead()) { if(!canSuffUndead) {
remove(player); for(int i = 0; i < targets.size(); i++) {
return; LivingEntity target = targets.get(i);
} if(Methods.isUndead(target)) {
targets.remove(i);
if (!Methods.canBend(player.getName(), "Suffocate")) { i--;
remove(player);
return;
}
if (Methods.getBoundAbility(player) == null || !Methods.getBoundAbility(player).equalsIgnoreCase("Suffocate")) {
remove(player);
return;
}
try {
for (Entity entity: targets.keySet()) {
if (!targets.keySet().iterator().hasNext()) {
remove(player);
return;
}
if (targets.isEmpty()) {
remove(player);
return;
}
if (isUndead(entity) && !canBeUsedOnUndead) {
breakSuffocate(entity);
continue;
}
if (entity.getLocation().getBlock() != null && Methods.isWater(entity.getLocation().getBlock())) {
breakSuffocate(entity);
continue;
}
if (Methods.isRegionProtectedFromBuild(player, "Suffocate", entity.getLocation())) {
remove(player);
continue;
}
if (entity.getLocation().distance(player.getLocation()) >= range) {
breakSuffocate(entity);
continue;
}
if (Methods.isObstructed(player.getLocation(), entity.getLocation())) {
breakSuffocate(entity);
continue;
}
if (entity instanceof Player) {
if (Commands.invincible.contains(((Player) entity).getName())) {
breakSuffocate(entity);
continue;
}
if (AvatarState.isAvatarState((Player) entity)) {
breakSuffocate(entity);
continue;
}
}
if (entity.isDead()) {
breakSuffocate(entity);
continue;
}
if (entity instanceof Creature) {
((Creature) entity).setTarget(player);
}
for(Location airsphere : Methods.getCircle(entity.getLocation(), 3, 3, false, true, 0)) {
Methods.playAirbendingParticles(airsphere, 1);
if (Methods.rand.nextInt(4) == 0) {
Methods.playAirbendingSound(airsphere);
}
}
entity.setFallDistance(0);
new TempPotionEffect((LivingEntity) entity, slow);
new TempPotionEffect((LivingEntity) entity, nausea);
if (System.currentTimeMillis() >= time + warmup) {
Methods.damageEntity(player, entity, damage);
entity.setVelocity(new Vector(0, 0, 0));
} }
} }
} catch (ConcurrentModificationException e) { }
if(targets.size() == 0)
return;
else if(bplayer.isOnCooldown("suffocate"))
return;
bplayer.addCooldown("suffocate", cooldown);
instances.put(player,this);
}
/** Progresses this instance of Suffocate by 1 tick. **/
public void progress() {
if(targets.size() == 0) {
remove();
return;
}
if (player.isDead() || !player.isOnline()) {
remove();
return;
}
String ability = Methods.getBoundAbility(player);
if(ability == null
|| !ability.equalsIgnoreCase("Suffocate")
|| !Methods.canBend(player.getName(), "Suffocate")) {
remove();
return;
}
for(int i = 0; i < targets.size(); i++) {
LivingEntity target = targets.get(i);
if(target.isDead()
|| !target.getWorld().equals(player.getWorld())
|| target.getLocation().distance(player.getEyeLocation()) > range) {
breakSuffocateLocal(target);
i--;
}
else if(target instanceof Player) {
Player targPlayer = (Player)target;
if(!targPlayer.isOnline()) {
breakSuffocateLocal(target);
i--;
}
}
}
if(targets.size() == 0) {
remove();
return;
}
if(reqConstantAim) {
double dist = player.getEyeLocation().distance(targets.get(0).getEyeLocation());
Location targetLoc = player.getEyeLocation().clone().add
(player.getEyeLocation().getDirection().normalize().multiply(dist));
List<Entity> ents = Methods.getEntitiesAroundPoint(targetLoc, aimRadius);
for(int i = 0; i < targets.size(); i++) {
LivingEntity target = targets.get(i);
if(!ents.contains(target)) {
breakSuffocateLocal(target);
i--;
}
}
if(targets.size() == 0) {
remove();
return;
}
}
if(System.currentTimeMillis() - time < chargeTime) {
return;
}
else if(!started) {
started = true;
final Player fplayer = player;
for(LivingEntity targ : targets) {
final LivingEntity target = targ;
BukkitRunnable br1 = new BukkitRunnable() {
@Override
public void run() {
Methods.damageEntity(fplayer, target, damage);
}
};
BukkitRunnable br2 = new BukkitRunnable() {
@Override
public void run() {
target.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, (int) (slowRepeat * 20), (int) slow));
}
};
BukkitRunnable br3 = new BukkitRunnable() {
@Override
public void run() {
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, (int) (blindRepeat * 20), (int) blind));
}
};
tasks.add(br1);
tasks.add(br2);
tasks.add(br3);
br1.runTaskTimer(ProjectKorra.plugin, (long) (damageDelay * 20), (long) (damageRepeat * 20));
br2.runTaskTimer(ProjectKorra.plugin, (long) (slowDelay * 20), (long) (slowRepeat * 20 / 0.25));
br3.runTaskTimer(ProjectKorra.plugin, (long) (blindDelay * 20), (long) (blindRepeat * 20));
}
}
animate();
if(!player.isSneaking()) {
remove();
return;
} }
} }
/**
* Animates this instance of the Suffocate ability.
* Depending on the specific time (dt) the ability will create
* a different set of SuffocationSpirals.
*/
public void animate() {
long curTime = System.currentTimeMillis();
long dt = curTime - time - chargeTime;
int steps = 8 * particleScale;
long delay = 2 / particleScale;
long t1 = (long) (1500 * speedFactor);
long t2 = (long) (2500 * speedFactor);
long t3 = (long) (5000 * speedFactor);
long t4 = (long) (6000 * speedFactor);
for(LivingEntity lent : targets) {
final LivingEntity target = lent;
if(dt < t1) {
new SuffocateSpiral(target, steps, radius, delay, 0, 0.25 - (0.25 * (double)dt / (double)t1), 0, SpiralType.HORIZONTAL1);
new SuffocateSpiral(target, steps, radius, delay, 0, 0.25 - (0.25 * (double)dt / (double)t1), 0, SpiralType.HORIZONTAL2);
}
else if(dt < t2) {
new SuffocateSpiral(target, steps, radius, delay, 0, 0, 0, SpiralType.HORIZONTAL1);
new SuffocateSpiral(target, steps * 2, radius, delay, 0, 0, 0, SpiralType.VERTICAL1);
new SuffocateSpiral(target, steps * 2, radius, delay, 0, 0, 0, SpiralType.VERTICAL2);
}
else if(dt < t3) {
new SuffocateSpiral(target, steps, radius, delay, 0, 0, 0, SpiralType.HORIZONTAL1);
new SuffocateSpiral(target, steps, radius, delay, 0, 0, 0, SpiralType.VERTICAL1);
new SuffocateSpiral(target, steps, radius, delay, 0, 0, 0, SpiralType.VERTICAL2);
}
else if(dt < t4) {
new SuffocateSpiral(target, steps, radius - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double)(dt - t3) / (double)(t4 - t3)))), delay, 0, 0, 0, SpiralType.HORIZONTAL1);
new SuffocateSpiral(target, steps, radius - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double)(dt - t3) / (double)(t4 - t3)))), delay, 0, 0, 0, SpiralType.VERTICAL1);
new SuffocateSpiral(target, steps, radius - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double)(dt - t3) / (double)(t4 - t3)))), delay, 0, 0, 0, SpiralType.VERTICAL2);
}
else {
new SuffocateSpiral(target, steps, radius - (radius * 3.0 / 4.0), delay, 0, 0, 0, SpiralType.HORIZONTAL1);
new SuffocateSpiral(target, steps, radius - (radius * 3.0 / 4.0), delay, 0, 0, 0, SpiralType.VERTICAL1);
new SuffocateSpiral(target, steps, radius - (radius * 3.0 / 4.0), delay, 0, 0, 0, SpiralType.VERTICAL2);
}
}
}
/** **
* Animates a Spiral of air particles around a location or a targetted entity.
* The direction of the spiral is determined by SpiralType, and each type
* is calculated independently from one another.
*/
public class SuffocateSpiral extends BukkitRunnable {
private Location startLoc;
private Location loc;
private LivingEntity target;
private int totalSteps;
private double radius;
private double dx, dy, dz;
private SpiralType type;
private int i;
/**
* @param startLoc: initial location
* @param totalSteps: amount of times it will be animated
* @param radius: the radius of the spiral
* @param interval: the speed of the animation
* @param dx: x offset
* @param dy: y offset
* @param dz: z offset
* @param type: spiral animation direction
*/
public SuffocateSpiral(Location startLoc, int totalSteps, double radius,
long interval, double dx, double dy, double dz, SpiralType type) {
this.startLoc = startLoc;
this.totalSteps = totalSteps;
this.radius = radius;
this.dx = dx;
this.dy = dy;
this.dz = dz;
this.type = type;
loc = startLoc.clone();
i = 0;
this.runTaskTimer(ProjectKorra.plugin, 0L, interval);
tasks.add(this);
}
/**
* @param lent: the entity to animate the spiral around
* @param totalSteps: amount of times it will be animated
* @param radius: the radius of the spiral
* @param interval: the speed of the animation
* @param dx: x offset
* @param dy: y offset
* @param dz: z offset
* @param type: spiral animation direction
*/
public SuffocateSpiral(LivingEntity lent, int totalSteps, double radius,
long interval, double dx, double dy, double dz, SpiralType type) {
this.target = lent;
this.totalSteps = totalSteps;
this.radius = radius;
this.dx = dx;
this.dy = dy;
this.dz = dz;
this.type = type;
loc = target.getEyeLocation();
i = 0;
this.runTaskTimer(ProjectKorra.plugin, 0L, interval);
tasks.add(this);
}
/**
* Starts the initial animation, and removes
* itself when it is finished.
*/
public void run() {
Location tempLoc;
if(target != null) {
tempLoc = target.getEyeLocation();
tempLoc.setY(tempLoc.getY() - 0.5);
}
else
tempLoc = startLoc.clone();
if(type == SpiralType.HORIZONTAL1) {
loc.setX(tempLoc.getX() + radius * Math.cos(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setY(tempLoc.getY() + dy * i);
loc.setZ(tempLoc.getZ() + radius * Math.sin(Math.toRadians((double)i / (double)totalSteps * 360)));
}
else if(type == SpiralType.HORIZONTAL2) {
loc.setX(tempLoc.getX() + radius * -Math.cos(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setY(tempLoc.getY() + dy * i);
loc.setZ(tempLoc.getZ() + radius * -Math.sin(Math.toRadians((double)i / (double)totalSteps * 360)));
}
else if(type == SpiralType.VERTICAL1) {
loc.setX(tempLoc.getX() + radius * Math.sin(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setY(tempLoc.getY() + radius * Math.cos(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setZ(tempLoc.getZ() + dz * i);
}
else if(type == SpiralType.VERTICAL2) {
loc.setX(tempLoc.getX() + dx * i);
loc.setY(tempLoc.getY() + radius * Math.sin(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setZ(tempLoc.getZ() + radius * Math.cos(Math.toRadians((double)i / (double)totalSteps * 360)));
}
else if(type == SpiralType.DIAGONAL1) {
loc.setX(tempLoc.getX() + radius * Math.cos(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setY(tempLoc.getY() + radius * Math.sin(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setZ(tempLoc.getZ() + radius * -Math.cos(Math.toRadians((double)i / (double)totalSteps * 360)));
}
else if(type == SpiralType.DIAGONAL2) {
loc.setX(tempLoc.getX() + radius * Math.cos(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setY(tempLoc.getY() + radius * Math.sin(Math.toRadians((double)i / (double)totalSteps * 360)));
loc.setZ(tempLoc.getZ() + radius * Math.cos(Math.toRadians((double)i / (double)totalSteps * 360)));
}
Methods.getAirbendingParticles().display(loc, (float) 0, (float) 0, (float) 0, 0, 1);
if(i == totalSteps + 1)
this.cancel();
i++;
}
}
/** Progresses every instance of Suffocate by 1 tick **/
public static void progressAll() { public static void progressAll() {
for (Player player : instances.keySet()) { for(Suffocate suff : instances.values())
instances.get(player).progress(); suff.progress();
}
/** Removes this instance of the ability **/
public void remove() {
instances.remove(player);
for(int i = 0; i < tasks.size(); i++) {
tasks.get(i).cancel();
tasks.remove(i);
i--;
} }
} }
/** Removes all instances of Suffocate at loc within the radius threshold.
* The location of a Suffocate is defined at the benders location, not
* the location of the entities being suffocated.
* @param causer: the player causing this instance to be removed
* **/
public static boolean removeAtLocation(Player causer, Location loc, double radius) {
Iterator<Player> it = instances.keySet().iterator();
while(it.hasNext()) {
Player key = it.next();
Suffocate val = instances.get(key);
if (causer == null || !key.equals(causer)) {
Location playerLoc = val.getPlayer().getLocation();
if(playerLoc.getWorld().equals(loc.getWorld()) && playerLoc.distance(loc) <= radius) {
it.remove();
return true;
}
}
}
return false;
}
/** Removes an instance of Suffocate if player is the one suffocating entities **/
public static void remove(Player player) { public static void remove(Player player) {
if (instances.containsKey(player)) { if (instances.containsKey(player))
instances.remove(player); instances.get(player).remove();
}
/** Removes every instance of Suffocate **/
public static void removeAll() {
Enumeration<Player> keys = instances.keys();
while(keys.hasMoreElements()) {
instances.get(keys.nextElement()).remove();
} }
} }
public static void breakSuffocate(Entity entity) { /** Determines if a player is Suffocating entities **/
for (Player player : instances.keySet()) {
if (instances.get(player).targets.containsKey(entity)) {
instances.get(player).targets.remove(entity);
}
}
}
public static boolean isBreathbent(Entity entity) {
for (Player player : instances.keySet()) {
if (instances.get(player).targets.containsKey(entity)) {
if (System.currentTimeMillis() >= instances.get(player).time + instances.get(player).warmup) {
return true;
}
return false;
}
}
return false;
}
public static boolean isUndead(Entity entity) {
if (entity == null) return false;
if (entity.getType() == EntityType.ZOMBIE
|| entity.getType() == EntityType.BLAZE
|| entity.getType() == EntityType.GIANT
|| entity.getType() == EntityType.IRON_GOLEM
|| entity.getType() == EntityType.MAGMA_CUBE
|| entity.getType() == EntityType.PIG_ZOMBIE
|| entity.getType() == EntityType.SKELETON
|| entity.getType() == EntityType.SLIME
|| entity.getType() == EntityType.SNOWMAN
|| entity.getType() == EntityType.ZOMBIE) {
return true;
}
return false;
}
public static boolean isChannelingSphere(Player player){ public static boolean isChannelingSphere(Player player){
if(instances.containsKey(player)) return true; if(instances.containsKey(player)) return true;
return false; return false;
} }
public static void removeAll() { /** Stops an entity from being suffocated **/
instances.clear(); public void breakSuffocateLocal(Entity entity) {
if (targets.contains(entity))
targets.remove(entity);
} }
/** Stops an entity from being suffocated **/
public static void breakSuffocate(Entity entity) {
for (Player player : instances.keySet()) {
if (instances.get(player).targets.contains(entity)) {
instances.get(player).breakSuffocateLocal(entity);
}
}
}
/** Checks if an entity is being suffocated **/
public static boolean isBreathbent(Entity entity) {
for (Player player : instances.keySet()) {
if (instances.get(player).targets.contains(entity)) {
return instances.get(player).started;
}
}
return false;
}
public static ConcurrentHashMap<Player, Suffocate> getInstances() {
return instances;
}
public Player getPlayer() {
return player;
}
public boolean isStarted() {
return started;
}
public void setStarted(boolean started) {
this.started = started;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public ArrayList<BukkitRunnable> getTasks() {
return tasks;
}
public void setTasks(ArrayList<BukkitRunnable> tasks) {
this.tasks = tasks;
}
public ArrayList<LivingEntity> getTargets() {
return targets;
}
public void setTargets(ArrayList<LivingEntity> targets) {
this.targets = targets;
}
public boolean isReqConstantAim() {
return reqConstantAim;
}
public void setReqConstantAim(boolean reqConstantAim) {
this.reqConstantAim = reqConstantAim;
}
public boolean isCanSuffUndead() {
return canSuffUndead;
}
public void setCanSuffUndead(boolean canSuffUndead) {
this.canSuffUndead = canSuffUndead;
}
public long getChargeTime() {
return chargeTime;
}
public void setChargeTime(long chargeTime) {
this.chargeTime = chargeTime;
}
public long getCooldown() {
return cooldown;
}
public void setCooldown(long cooldown) {
this.cooldown = cooldown;
}
public int getParticleScale() {
return particleScale;
}
public void setParticleScale(int particleScale) {
this.particleScale = particleScale;
}
public double getRange() {
return range;
}
public void setRange(double range) {
this.range = range;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getSpeedFactor() {
return speedFactor;
}
public void setSpeedFactor(double speedFactor) {
this.speedFactor = speedFactor;
}
public double getAimRadius() {
return aimRadius;
}
public void setAimRadius(double aimRadius) {
this.aimRadius = aimRadius;
}
public double getDamage() {
return damage;
}
public void setDamage(double damage) {
this.damage = damage;
}
public double getDamageDelay() {
return damageDelay;
}
public void setDamageDelay(double damageDelay) {
this.damageDelay = damageDelay;
}
public double getDamageRepeat() {
return damageRepeat;
}
public void setDamageRepeat(double damageRepeat) {
this.damageRepeat = damageRepeat;
}
public double getSlow() {
return slow;
}
public void setSlow(double slow) {
this.slow = slow;
}
public double getslowRepeat() {
return slowRepeat;
}
public void setslowRepeat(double slowRepeat) {
this.slowRepeat = slowRepeat;
}
public double getSlowDelay() {
return slowDelay;
}
public void setSlowDelay(double slowDelay) {
this.slowDelay = slowDelay;
}
public double getBlind() {
return blind;
}
public void setBlind(double blind) {
this.blind = blind;
}
public double getBlindDelay() {
return blindDelay;
}
public void setBlindDelay(double blindDelay) {
this.blindDelay = blindDelay;
}
public double getBlindRepeat() {
return blindRepeat;
}
public void setBlindRepeat(double blindRepeat) {
this.blindRepeat = blindRepeat;
}
} }

View file

@ -161,9 +161,24 @@ Abilities:
Suffocate: Suffocate:
Enabled: true Enabled: true
Description: "This ability is one of the most dangerous abilities an Airbender possesses. To use, simply look at an entity and hold shift. The entity will begin taking damage as you extract the air from their lungs. Any bender caught in this sphere will only be able to use basic moves, such as AirSwipe, WaterManipulation, FireBlast, or EarthBlast. An entity can be knocked out of the sphere by certain bending arts, and your attention will be disrupted if you are hit by bending." Description: "This ability is one of the most dangerous abilities an Airbender possesses. To use, simply look at an entity and hold shift. The entity will begin taking damage as you extract the air from their lungs. Any bender caught in this sphere will only be able to use basic moves, such as AirSwipe, WaterManipulation, FireBlast, or EarthBlast. An entity can be knocked out of the sphere by certain bending arts, and your attention will be disrupted if you are hit by bending."
Range: 15
Damage: 2
ChargeTime: 1000
Cooldown: 0
DamageInitialDelay: 2
DamageInterval: 1
SlowPotency: 1
SlowDelay: 0.5
SlowInterval: 1.25
BlindPotentcy: 30
BlindDelay: 2
BlindInterval: 1.5
CanBeUsedOnUndeadMobs: true CanBeUsedOnUndeadMobs: true
Range: 5 RequireConstantAim: true
Damage: 0.5 RequireConstantAimRadius: 5
AnimationRadius: 2.0
AnimationParticleAmount: 2
AnimationSpeed: 1.0
Tornado: Tornado:
Enabled: true Enabled: true
Description: "To use, simply sneak (default: shift). This will create a swirling vortex at the targeted location. Any creature or object caught in the vortex will be launched up and out in some random direction. If another player gets caught in the vortex, the launching effect is minimal. Tornado can also be used to transport the user. If the user gets caught in his/her own tornado, his/her movements are much more manageable. Provided the user doesn't fall out of the vortex, it will take him to a maximum height and move him in the general direction he/she is looking. Skilled airbenders can scale anything with this ability." Description: "To use, simply sneak (default: shift). This will create a swirling vortex at the targeted location. Any creature or object caught in the vortex will be launched up and out in some random direction. If another player gets caught in the vortex, the launching effect is minimal. Tornado can also be used to transport the user. If the user gets caught in his/her own tornado, his/her movements are much more manageable. Provided the user doesn't fall out of the vortex, it will take him to a maximum height and move him in the general direction he/she is looking. Skilled airbenders can scale anything with this ability."