Merge pull request #94 from nathank33/master

Suffocation Rework and Bug Fixes
This commit is contained in:
MistPhizzle 2015-02-01 18:54:47 -05:00
commit 68309215ed
13 changed files with 861 additions and 254 deletions

View file

@ -223,9 +223,24 @@ public class ConfigManager {
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.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.Range", 5);
config.addDefault("Abilities.Air.Suffocate.Damage", 0.5);
config.addDefault("Abilities.Air.Suffocate.RequireConstantAim", true);
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.Height", 25);

View file

@ -46,6 +46,7 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.FallingSand;
import org.bukkit.entity.LivingEntity;
@ -1456,15 +1457,22 @@ public class Methods {
ConcurrentHashMap<Block, BlockCacheElement> blockMap = blockProtectionCache.get(player.getName());
Block block = loc.getBlock();
if(blockMap.containsKey(block))
return blockMap.get(block).isAllowed();
if(blockMap.containsKey(block)) {
BlockCacheElement elem = blockMap.get(block);
// both abilities must be equal to each other to use the cache
if((ability == null && elem.getAbility() == null)
|| (ability != null && elem.getAbility() != null && elem.getAbility().equals(ability))) {
return elem.isAllowed();
}
}
boolean value = isRegionProtectedFromBuildPostCache(player, ability, loc);
blockMap.put(block, new BlockCacheElement(player, block, value, System.currentTimeMillis()));
blockMap.put(block, new BlockCacheElement(player, block, ability, value, System.currentTimeMillis()));
return value;
}
private static boolean isRegionProtectedFromBuildPostCache(Player player, String ability, Location loc) {
public static boolean isRegionProtectedFromBuildPostCache(Player player, String ability, Location loc) {
boolean allowharmless = plugin.getConfig().getBoolean("Properties.RegionProtection.AllowHarmlessAbilities");
boolean respectWorldGuard = plugin.getConfig().getBoolean("Properties.RegionProtection.RespectWorldGuard");
@ -1522,7 +1530,7 @@ public class Methods {
if (explode.contains(ability)) {
if (wg.getGlobalStateManager().get(location.getWorld()).blockTNTExplosions)
return true;
if (wg.getRegionContainer().createQuery().testBuild(location, player, DefaultFlag.TNT))
if (!wg.getRegionContainer().createQuery().testBuild(location, player, DefaultFlag.TNT))
return true;
}
@ -2661,19 +2669,21 @@ public class Methods {
if(!canBend(player.getName(), "Flight")) return false;
if(!getBoundAbility(player).equalsIgnoreCase("Flight")) return false;
if(isRegionProtectedFromBuild(player, "Flight", player.getLocation())) return false;
if(player.getLocation().subtract(0, 1, 0).getBlock().getType() != Material.AIR) return false;
if(player.getLocation().subtract(0, 0.5, 0).getBlock().getType() != Material.AIR) return false;
return true;
}
public static class BlockCacheElement {
private Player player;
private Block block;
private String ability;
private boolean allowed;
private long time;
public BlockCacheElement(Player player, Block block, boolean allowed, long time) {
public BlockCacheElement(Player player, Block block, String ability, boolean allowed, long time) {
this.player = player;
this.block = block;
this.ability = ability;
this.allowed = allowed;
this.time = time;
}
@ -2710,6 +2720,14 @@ public class Methods {
this.allowed = allowed;
}
public String getAbility() {
return ability;
}
public void setAbility(String ability) {
this.ability = ability;
}
}
public static void startCacheCleaner(final double period) {
@ -2729,5 +2747,22 @@ public class Methods {
}.runTaskTimer(ProjectKorra.plugin, 0, (long) (period / 20));
}
/** Checks if an entity is Undead **/
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;
}
}

View file

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

View file

@ -13,6 +13,7 @@ import org.bukkit.util.Vector;
import com.projectkorra.ProjectKorra.BendingPlayer;
import com.projectkorra.ProjectKorra.ComboManager.ClickType;
import com.projectkorra.ProjectKorra.Commands;
import com.projectkorra.ProjectKorra.Element;
import com.projectkorra.ProjectKorra.Flight;
import com.projectkorra.ProjectKorra.Methods;
import com.projectkorra.ProjectKorra.ProjectKorra;
@ -99,11 +100,13 @@ public class AirCombo {
public AirCombo(Player player, String ability) {
if (!enabled || !player.hasPermission("bending.ability.AirCombo"))
return;
if (Methods.isRegionProtectedFromBuild(player, "AirBlast",
player.getLocation()))
if(!Methods.getBendingPlayer(player.getName()).hasElement(Element.Air))
return;
if (Commands.isToggledForAll)
return;
if (Methods.isRegionProtectedFromBuild(player, "AirBlast",
player.getLocation()))
return;
if (!Methods.getBendingPlayer(player.getName()).isToggled())
return;
time = System.currentTimeMillis();

View file

@ -1,10 +1,12 @@
package com.projectkorra.ProjectKorra.airbending;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import com.projectkorra.ProjectKorra.Flight;
import com.projectkorra.ProjectKorra.Methods;
public class FlightAbility {
@ -13,15 +15,13 @@ public class FlightAbility {
private static ConcurrentHashMap<String, Integer> hits = new ConcurrentHashMap<String, Integer>();
private static ConcurrentHashMap<String, Boolean> hovering = new ConcurrentHashMap<String, Boolean>();
private Player p;
private Flight flight;
public FlightAbility(Player player) {
if(!Methods.canFly(player, true, false)) return;
if(!Methods.canFly(player, true, false))
return;
player.setAllowFlight(true);
player.setVelocity(player.getEyeLocation().getDirection().normalize());
instances.put(player.getName(), this);
p = player;
}
@ -32,11 +32,20 @@ public class FlightAbility {
return;
}
p.setAllowFlight(true);
if(flight == null)
flight = new Flight(p);
if(isHovering(p)) {
Vector vec = p.getVelocity().clone();
vec.setY(0);
p.setVelocity(vec);
}
else {
p.setVelocity(p.getEyeLocation().getDirection().normalize());
}
}
public static void addHit(Player player) {
if(instances.containsKey(player)) {
if(hits.containsKey(player.getName())) {
@ -51,11 +60,7 @@ public class FlightAbility {
}
public static boolean isHovering(Player player) {
String playername = player.getName();
if(hovering.containsKey(playername) && hovering.get(playername)) return true;
if(hovering.containsKey(playername) && hovering.get(playername)) return false; //Shouldn't happen
return false;
return hovering.containsKey(player.getName());
}
public static void setHovering(Player player, boolean bool) {
@ -64,13 +69,11 @@ public class FlightAbility {
if(bool) {
if(!hovering.containsKey(playername)) {
hovering.put(playername, true);
player.setFlying(true);
player.setVelocity(new Vector(0, 0, 0));
}
}else{
if(hovering.containsKey(playername)) {
hovering.remove(playername);
player.setFlying(false);
}
}
}
@ -81,30 +84,24 @@ public class FlightAbility {
}
}
@SuppressWarnings("deprecation")
public void remove() {
String name = p.getName();
instances.remove(name);
hits.remove(name);
hovering.remove(name);
flight.revert();
}
public static void remove(Player player) {
if(instances.containsKey(player.getName())) {
instances.remove(player.getName());
if(hits.containsKey(player.getName())) {
hits.remove(player.getName());
}
if(hovering.containsKey(player.getName())) {
hovering.remove(player.getName());
}
if((!(player.getGameMode().getValue() == 1))) {
if(!(player.getGameMode().getValue() == 1)) {
player.setAllowFlight(false);
}
}
if((!(player.getGameMode().getValue() == 3))) {
if(!(player.getGameMode().getValue() == 1)) {
player.setAllowFlight(false);
}
}
}
if(instances.containsKey(player.getName()))
instances.get(player.getName()).remove();
}
public static void removeAll() {
Iterator<String> it = instances.keySet().iterator();
while (it.hasNext()) {
instances.get(it.next()).remove();
}
instances.clear();
hits.clear();
hovering.clear();

View file

@ -1,220 +1,682 @@
package com.projectkorra.ProjectKorra.airbending;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Location;
import org.bukkit.entity.Creature;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
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 org.bukkit.scheduler.BukkitRunnable;
import com.projectkorra.ProjectKorra.Commands;
import com.projectkorra.ProjectKorra.BendingPlayer;
import com.projectkorra.ProjectKorra.Methods;
import com.projectkorra.ProjectKorra.ProjectKorra;
import com.projectkorra.ProjectKorra.TempPotionEffect;
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 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 int range = ProjectKorra.plugin.getConfig().getInt("Abilities.Air.Suffocate.Range");
private double damage = ProjectKorra.plugin.getConfig().getDouble("Abilities.Air.Suffocate.Damage");
private static FileConfiguration config = ProjectKorra.plugin.getConfig();
private static final boolean CAN_SUFFOCATE_UNDEAD = config.getBoolean("Abilities.Air.Suffocate.CanBeUsedOnUndeadMobs");
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 BendingPlayer bplayer;
private boolean started = false;
private long time;
private long warmup = 2000;
private PotionEffect slow = new PotionEffect(PotionEffectType.SLOW, 60, 1);
private PotionEffect nausea = new PotionEffect(PotionEffectType.SLOW, 60, 1);
private ArrayList<BukkitRunnable> tasks;
private ArrayList<LivingEntity> targets;
private boolean reqConstantAim;
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) {
if (instances.containsKey(player)) {
remove(player);
this.player = player;
bplayer = Methods.getBendingPlayer(player.getName());
targets = new ArrayList<LivingEntity>();
tasks = new ArrayList<BukkitRunnable>();
time = System.currentTimeMillis();
reqConstantAim = REQUIRE_CONSTANT_AIM;
canSuffUndead = CAN_SUFFOCATE_UNDEAD;
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;
}
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());
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);
}
}
} 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());
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(!canSuffUndead) {
for(int i = 0; i < targets.size(); i++) {
LivingEntity target = targets.get(i);
if(Methods.isUndead(target)) {
targets.remove(i);
i--;
}
}
}
this.player = player;
if(targets.size() == 0)
return;
else if(bplayer.isOnCooldown("suffocate"))
return;
bplayer.addCooldown("suffocate", cooldown);
instances.put(player,this);
time = System.currentTimeMillis();
}
private void progress() {
/** 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(player);
remove();
return;
}
if (player.isDead()) {
remove(player);
return;
}
if (!Methods.canBend(player.getName(), "Suffocate")) {
remove(player);
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);
}
if (Methods.getBoundAbility(player) == null || !Methods.getBoundAbility(player).equalsIgnoreCase("Suffocate")) {
remove(player);
return;
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);
}
try {
for (Entity entity: targets.keySet()) {
if (!targets.keySet().iterator().hasNext()) {
remove(player);
return;
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);
}
if (targets.isEmpty()) {
remove(player);
return;
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);
}
if (isUndead(entity) && !canBeUsedOnUndead) {
breakSuffocate(entity);
continue;
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);
}
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;
/** **
* 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);
}
if (entity instanceof Creature) {
((Creature) entity).setTarget(player);
/**
* @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);
}
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);
/**
* 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);
}
}
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) {
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() {
for (Player player : instances.keySet()) {
instances.get(player).progress();
}
for(Suffocate suff : instances.values())
suff.progress();
}
public static void remove(Player player) {
if (instances.containsKey(player)) {
/** 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--;
}
}
public static void breakSuffocate(Entity entity) {
for (Player player : instances.keySet()) {
if (instances.get(player).targets.containsKey(entity)) {
instances.get(player).targets.remove(entity);
}
}
}
/** 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);
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) {
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;
}
}
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;
/** Removes an instance of Suffocate if player is the one suffocating entities **/
public static void remove(Player player) {
if (instances.containsKey(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();
}
}
/** Determines if a player is Suffocating entities **/
public static boolean isChannelingSphere(Player player){
if(instances.containsKey(player)) return true;
return false;
}
public static void removeAll() {
instances.clear();
/** Stops an entity from being suffocated **/
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

@ -15,11 +15,11 @@ public class ChiblockingManager implements Runnable {
@Override
public void run() {
for(Player player : Bukkit.getOnlinePlayers()) {
ChiPassive.handlePassive();
Smokescreen.removeFromHashMap(player);
WarriorStance.progressAll();
AcrobatStance.progressAll();
for(Player player : Bukkit.getOnlinePlayers()) {
Smokescreen.removeFromHashMap(player);
}
}

View file

@ -545,10 +545,13 @@ public class EarthSmash {
for(EarthSmash smash : instances) {
//Check to see if the player is standing on top of the smash.
if(smash.state == State.LIFTED)
if(smash.loc.clone().add(0,2,0).distanceSquared(player.getLocation()) <= Math.pow(FLIGHT_DETECTION_RADIUS, 2))
if(smash.state == State.LIFTED) {
if(smash.loc.getWorld().equals(player.getWorld())
&& smash.loc.clone().add(0,2,0).distanceSquared(player.getLocation()) <= Math.pow(FLIGHT_DETECTION_RADIUS, 2)) {
return smash;
}
}
}
return null;
}

View file

@ -27,22 +27,38 @@ public class Extraction {
}
if (!Methods.isRegionProtectedFromBuild(player, "Extraction", block.getLocation())) {
if (Methods.canMetalbend(player) && Methods.canBend(player.getName(), "Extraction")) {
Material type = null;
switch(block.getType()) {
case IRON_ORE:
block.setType(Material.STONE);
player.getWorld().dropItem(player.getLocation(), new ItemStack(Material.IRON_INGOT, getAmount()));
type = Material.STONE;
break;
case GOLD_ORE:
block.setType(Material.STONE);
player.getWorld().dropItem(player.getLocation(), new ItemStack(Material.GOLD_INGOT, getAmount()));
type = Material.STONE;
break;
case QUARTZ_ORE:
block.setType(Material.NETHERRACK);
player.getWorld().dropItem(player.getLocation(), new ItemStack(Material.QUARTZ, getAmount()));
type = Material.NETHERRACK;
break;
default:
break; // shouldn't happen.
}
if(type != null) {
/* Update the block from Methods.movedearth to Stone otherwise
* players can use RaiseEarth > Extraction > Collapse
* to dupe the material from the block.
* */
if(Methods.movedearth.containsKey(block)) {
Methods.movedearth.remove(block);
}
}
Methods.playMetalbendingSound(block.getLocation());
bPlayer.addCooldown("Extraction", cooldown);
}

View file

@ -18,6 +18,7 @@ import org.bukkit.util.Vector;
import com.projectkorra.ProjectKorra.BendingPlayer;
import com.projectkorra.ProjectKorra.ComboManager.ClickType;
import com.projectkorra.ProjectKorra.Commands;
import com.projectkorra.ProjectKorra.Element;
import com.projectkorra.ProjectKorra.Methods;
import com.projectkorra.ProjectKorra.ProjectKorra;
import com.projectkorra.ProjectKorra.Ability.AvatarState;
@ -103,11 +104,13 @@ public class FireCombo {
// Dont' call Methods.canBind directly, it doesn't let you combo as fast
if (!enabled || !player.hasPermission("bending.ability.FireCombo"))
return;
if (Methods.isRegionProtectedFromBuild(player, "Blaze",
player.getLocation()))
if(!Methods.getBendingPlayer(player.getName()).hasElement(Element.Fire))
return;
if (Commands.isToggledForAll)
return;
if (Methods.isRegionProtectedFromBuild(player, "Blaze",
player.getLocation()))
return;
if (!Methods.getBendingPlayer(player.getName()).isToggled())
return;
time = System.currentTimeMillis();

View file

@ -59,7 +59,6 @@ public class Lightning {
private ArrayList<Entity> affectedEntities = new ArrayList<Entity>();
private ArrayList<Arc> arcs = new ArrayList<Arc>();
private ArrayList<BukkitRunnable> tasks = new ArrayList<BukkitRunnable>();
private HashMap<Block, Boolean> isTransparentCache = new HashMap<Block, Boolean>();
public Lightning(Player player) {
this.player = player;
@ -81,17 +80,16 @@ public class Lightning {
cooldown = COOLDOWN;
if(AvatarState.isAvatarState(player)) {
//range = AvatarState.getValue(range);
/* Some variables aren't considered here because it makes AS too overpowered
* and causes crashing.
*/
chargeTime = 0;
cooldown = 0;
//subArcChance = AvatarState.getValue(subArcChance);
damage = AvatarState.getValue(damage);
chainArcs = AvatarState.getValue(chainArcs);
chainArcChance = AvatarState.getValue(chainArcChance);
chainRange = AvatarState.getValue(chainRange);
//waterRange = AvatarState.getValue(waterRange);
stunChance = AvatarState.getValue(stunChance);
//stunDuration = AvatarState.getValue(stunDuration);
}
else if(BendingManager.events.containsKey(player.getWorld())) {
if (BendingManager.events.get(player.getWorld()).equalsIgnoreCase("SozinsComet")) {
@ -102,6 +100,7 @@ public class Lightning {
instances.add(this);
}
/** Displays Redstone particles at the players eye location **/
public void displayChargedParticles() {
Location l = player.getEyeLocation().add(player.getEyeLocation().getDirection().normalize().multiply(1));
l.setX(l.getX() + Math.random() * (0.1 - -0.1));
@ -111,6 +110,13 @@ public class Lightning {
ParticleEffect.RED_DUST.display((float) 0, (float) 255, (float) 255, 0.1F, 0, l, 256D);
}
/** Progresses the instance of this ability by 1 tick.
* This is the heart of the ability, it checks if it needs to
* remove itself, and handles the initial Lightning Arc generation.
*
* Once all of the arcs have been created then this ability instance
* gets removed, but the BukkitRunnables continue until they remove
* themselves. **/
private void progress() {
if (player.isDead() || !player.isOnline()) {
removeWithTasks();
@ -191,25 +197,23 @@ public class Lightning {
}
}
/** Checks if a block is transparent, also considers the ARC_ON_ICE config option **/
public boolean isTransparent(Player player, Block block) {
if(isTransparentCache.containsKey(block))
return isTransparentCache.get(block);
boolean value = false;
if (Arrays.asList(Methods.transparentToEarthbending).contains(block.getTypeId())) {
if(Methods.isRegionProtectedFromBuild(player, "Lightning", block.getLocation()))
value = false;
return false;
else if(isIce(block.getLocation()))
value = ARC_ON_ICE;
return ARC_ON_ICE;
else
value = true;
return true;
}
else
value = false;
isTransparentCache.put(block, new Boolean(value));
return value;
return false;
}
/**
* Damages an entity, and may cause paralysis depending on the config.
* @param lent: the LivingEntity that is being damaged
*/
public void electrocute(LivingEntity lent) {
lent.getWorld().playSound(lent.getLocation(), Sound.CREEPER_HISS, 1, 0);
player.getWorld().playSound(player.getLocation(), Sound.CREEPER_HISS, 1, 0);
@ -239,6 +243,7 @@ public class Lightning {
}
}
/** Removes the instance of this ability and cancels any current runnables **/
public void removeWithTasks() {
for(int i = 0; i < tasks.size(); i++) {
tasks.get(i).cancel();
@ -246,10 +251,12 @@ public class Lightning {
}
remove();
}
public void remove() {
/** Removes this ability instance **/ public void remove() {
instances.remove(this);
}
/** Removes every instance of this ability **/
public static void removeAll() {
for (int i = 0; i < instances.size(); i++) {
instances.get(i).remove();
@ -257,11 +264,13 @@ public class Lightning {
}
}
/** Progresses every instance of this ability by 1 tick **/
public static void progressAll() {
for (int i = 0; i < instances.size(); i++)
instances.get(i).progress();
}
/** Returns an instance of this ability if it was initialized by player **/
public static Lightning getLightning(Player player) {
for(Lightning light : instances) {
if(light.player == player)
@ -270,16 +279,19 @@ public class Lightning {
return null;
}
/** Checks if a location contains an ice block **/
public static boolean isIce(Location loc) {
Material mat = loc.getBlock().getType();
return mat == Material.ICE || mat == Material.PACKED_ICE;
}
/** Checks if a location contains a water block **/
public static boolean isWater(Location loc) {
Material mat = loc.getBlock().getType();
return mat == Material.WATER || mat == Material.STATIONARY_WATER;
}
/** Checks if a location is ice or water **/
public static boolean isWaterOrIce(Location loc) {
return isIce(loc) || isWater(loc);
}
@ -289,6 +301,10 @@ public class Lightning {
+ "charged, release sneak to discharge the lightning to the targetted location.";
}
/** An Arc represents a Lightning arc for the specific ability.
* These Arcs contain a list of Particles that are used to display
* the entire arc. Arcs can also generate a list of subarcs that
* chain off of their own instance.**/
public class Arc {
private ArrayList<Location> points;
private ArrayList<AnimLocation> animLocs;
@ -308,6 +324,16 @@ public class Lightning {
animCounter = 0;
}
/** Runs an arc generation algorithm by first creating two points,
* the starting point and the ending point. Next, it creates a point
* in the middle that has an offset relative to the beginning and
* end points. Now that the arc is split into 3 points, we continue this
* processes by generating middle points in the two halfs of this arc.
* This process continues based on @times
*
* @param times: The amount of times that the arc will be split in half
* @param times causes O(n^2) complexity
* **/
public void generatePoints(int times) {
for(int i = 0; i < times; i++) {
for(int j = 0; j < points.size() - 1; j += 2) {
@ -330,6 +356,12 @@ public class Lightning {
}
}
/** Randomly generates subarcs off of this arc.
* @param chance - The chance that an arc will be generated
* for each specific point in the arc.
* Note: if you generate a lot of points then chance will need to be lowered.
* @param range: The length of each subarc.
* **/
public ArrayList<Arc> generateArcs(double chance, double range) {
ArrayList<Arc> arcs = new ArrayList<Arc>();
for(int i = 0; i < animLocs.size(); i++) {
@ -350,6 +382,7 @@ public class Lightning {
return arcs;
}
/** Stops this Arc from further animating or doing damage. **/
public void cancel() {
for(int i = 0; i < particles.size(); i++) {
particles.get(i).cancel();
@ -360,10 +393,12 @@ public class Lightning {
}
}
/** Gets every point that makes up this arc. **/
public ArrayList<Location> getPoints() {
return points;
}
/** Below are accessor and mutators**/
public void setPoints(ArrayList<Location> points) {
this.points = points;
}
@ -402,6 +437,9 @@ public class Lightning {
}
/** Represents a Lightning Arc Point particle animation.
* This basically just holds a location and counts the
* amount of times that a particle has been animated. **/
public class AnimLocation {
private Location loc;
private int animCounter;
@ -428,6 +466,13 @@ public class Lightning {
}
}
/** A Runnable Particle that continuously displays itself
* until it reaches a certain time limit.
*
* These LightningParticles do the actual checking for player collision
* and handle damaging any entities. These Runnables also
* check to see if they reach water, in which case they will generate
* subarcs to branch out.**/
public class LightningParticle extends BukkitRunnable {
private Arc arc;
private Location loc;
@ -439,11 +484,16 @@ public class Lightning {
arc.particles.add(this);
}
/** Cancels this Runnable**/
public void cancel() {
super.cancel();
tasks.remove(this);
}
/**
* Animates the Location, checks for water/player collision
* and also deals with any chain subarcs.
*/
public void run() {
ParticleEffect.RED_DUST.display((float) 0, (float) 255, (float) 255, 0.1F, 0, loc, 256D);
count++;
@ -518,6 +568,7 @@ public class Lightning {
}
}
/** Below are all of the accessor/mutator methods **/
public Player getPlayer() {
return player;
}

View file

@ -15,6 +15,7 @@ import org.bukkit.util.Vector;
import com.projectkorra.ProjectKorra.BendingPlayer;
import com.projectkorra.ProjectKorra.Commands;
import com.projectkorra.ProjectKorra.Element;
import com.projectkorra.ProjectKorra.Methods;
import com.projectkorra.ProjectKorra.ProjectKorra;
import com.projectkorra.ProjectKorra.TempBlock;
@ -81,11 +82,13 @@ public class WaterCombo {
public WaterCombo(Player player, String ability) {
if (!enabled || !player.hasPermission("bending.ability.WaterCombo"))
return;
if (Methods.isRegionProtectedFromBuild(player, "WaterManipulation",
player.getLocation()))
if(!Methods.getBendingPlayer(player.getName()).hasElement(Element.Water))
return;
if (Commands.isToggledForAll)
return;
if (Methods.isRegionProtectedFromBuild(player, "WaterManipulation",
player.getLocation()))
return;
if (!Methods.getBendingPlayer(player.getName()).isToggled())
return;
time = System.currentTimeMillis();

View file

@ -161,9 +161,24 @@ Abilities:
Suffocate:
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."
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
Range: 5
Damage: 0.5
RequireConstantAim: true
RequireConstantAimRadius: 5
AnimationRadius: 2.0
AnimationParticleAmount: 2
AnimationSpeed: 1.0
Tornado:
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."