TF-ProjectKorra/src/com/projectkorra/projectkorra/waterbending/ice/IceBlast.java
Christopher Martin 102112ffdd 1.8.6 (#825)
## Fixes
* Fixed Combos and possibly Passives appearing in `/pk b <Ability>` auto-tabbing.
* Fixed Combos not loading properly on certain servers.
* Fixed issue with `PreciousStones` by updating to the latest version to resolve API change issues.
* Fixed `RapidPunch` damage.
* Fixed incorrect summation of chiblocking chance.
* Fixed possible issue in PKListener#onPlayerInteraction()
* Fixed `Earth.LavaSound`.
* Fixed Chi attempting to chiblock targets with any move.
* Fixed hitting an entity with `TempArmor` not ignoring armor.
* Fixed `Immobilize` config path.

## Additions
* Added "Contributing" section to the `README` to help guide active community members.
* Added more detail to the `PULL_REQUEST_TEMPLATE` to allow for more uniform pull requests. 
* Added many new blocks to our ability block interaction.
* Added check to combo collisions to discard dead entities.
* Added functionality to allow chiblocking abilities to affect all entities.
* Added exception handling to the configurable `Sound` options to prevent `IllegalArgumentExcpetions`.
* Added sounds and `ActionBar` messages to being Bloodbent, Electrocuted, Immobilized, MetalClipped, and Paralyzed. (Abilities: `Bloodbending`, `Lightning`, `Immobilize`, `MetalClips`, and `Paralyze`)
* Added sound and `ActionBar` message for being Chiblocked.
* Added interval config option to `RapidPunch`. (time between each punch)

## API Changes
* Updated to `Spigot 1.12.1`.
    * Confirmed to be backward compatible with `Spigot 1.12` and `Spigot 1.11.2`.
* Renamed `ElementalAbility#getTransparentMaterial()` to `ElementalAbility#getTransparentMaterials()`.
* Converted most `byte`/`int` dependent `Material` logic to use `Material` instead. 
    * `ElementalAbility#getTransparentMaterialSet()` now returns a `HashSet<Material>` instead of a `HashSet<Byte>`.
    * `ElementalAbility#getTransparentMaterials()` and `GeneralMethods.NON_OPAQUE` now return `Material[]` instead of `Integer[]`.
    * `GeneralMethods#getTargetedLocation()` now takes a `varargs Material[]` instead of a `varargs Integer[]`.
* Removed `ElementalAbility.TRANSPARENT_MATERIAL`. It was outdated and became irrelevent after `GeneralMethods.NON_OPAQUE` was updated.
* Removed `Java 7` Travi-CI  JDK check.
* Updated `pom.xml` to build in `Java 8`.
* Added new `MovementHandler` utility class to control entity movement. (currently only capable of stopping movement.
2017-08-06 00:18:12 -07:00

484 lines
12 KiB
Java

package com.projectkorra.projectkorra.waterbending.ice;
import com.projectkorra.projectkorra.BendingPlayer;
import com.projectkorra.projectkorra.GeneralMethods;
import com.projectkorra.projectkorra.ability.AirAbility;
import com.projectkorra.projectkorra.ability.IceAbility;
import com.projectkorra.projectkorra.util.BlockSource;
import com.projectkorra.projectkorra.util.ClickType;
import com.projectkorra.projectkorra.util.DamageHandler;
import com.projectkorra.projectkorra.util.ParticleEffect;
import com.projectkorra.projectkorra.util.TempBlock;
import com.projectkorra.projectkorra.util.TempPotionEffect;
import com.projectkorra.projectkorra.waterbending.util.WaterReturn;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
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 java.util.ArrayList;
import java.util.Random;
public class IceBlast extends IceAbility {
private boolean prepared;
private boolean settingUp;
private boolean progressing;
private byte data;
private long time;
private long cooldown;
private long interval;
private double range;
private double damage;
private double collisionRadius;
private double deflectRange;
private Block sourceBlock;
private Location location;
private Location firstDestination;
private Location destination;
public TempBlock source;
public IceBlast(Player player) {
super(player);
this.data = 0;
this.interval = getConfig().getLong("Abilities.Water.IceBlast.Interval");
this.collisionRadius = getConfig().getDouble("Abilities.Water.IceBlast.CollisionRadius");
this.deflectRange = getConfig().getDouble("Abilities.Water.IceBlast.DeflectRange");
this.range = getConfig().getDouble("Abilities.Water.IceBlast.Range");
this.damage = getConfig().getInt("Abilities.Water.IceBlast.Damage");
this.cooldown = getConfig().getInt("Abilities.Water.IceBlast.Cooldown");
this.damage = getNightFactor(damage, player.getWorld());
if (!bPlayer.canBend(this) || !bPlayer.canIcebend()) {
return;
}
if (bPlayer.isAvatarState()) {
this.cooldown = 0;
this.range = getConfig().getDouble("Abilities.Avatar.AvatarState.Water.IceBlast.Range");
this.damage = getConfig().getInt("Abilities.Avatar.AvatarState.Water.IceBlast.Damage");
}
block(player);
range = getNightFactor(range, player.getWorld());
Block sourceBlock = BlockSource.getWaterSourceBlock(player, range, ClickType.SHIFT_DOWN, false, true, false, false, false);
if (sourceBlock == null) {
return;
} else if (GeneralMethods.isRegionProtectedFromBuild(this, sourceBlock.getLocation())) {
return;
} else {
prepare(sourceBlock);
}
}
private void prepare(Block block) {
for (IceBlast iceBlast : getAbilities(player, IceBlast.class)) {
if (iceBlast.prepared) {
iceBlast.remove();
}
}
sourceBlock = block;
location = sourceBlock.getLocation();
prepared = true;
if (getAbilities(player, IceBlast.class).isEmpty()) {
start();
}
}
private static void block(Player player) {
for (IceBlast iceBlast : getAbilities(IceBlast.class)) {
if (!iceBlast.location.getWorld().equals(player.getWorld())) {
continue;
} else if (!iceBlast.progressing) {
continue;
} else if (iceBlast.getPlayer().equals(player)) {
continue;
} else if (GeneralMethods.isRegionProtectedFromBuild(iceBlast, iceBlast.location)) {
continue;
}
Location location = player.getEyeLocation();
Vector vector = location.getDirection();
Location mloc = iceBlast.location;
if (mloc.distanceSquared(location) <= iceBlast.range * iceBlast.range && GeneralMethods.getDistanceFromLine(vector, location, iceBlast.location) < iceBlast.deflectRange && mloc.distanceSquared(location.clone().add(vector)) < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) {
iceBlast.remove();
}
}
}
public static void activate(Player player) {
BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player);
if (bPlayer != null && bPlayer.isOnCooldown("IceBlast")) {
return;
}
for (IceBlast ice : getAbilities(IceBlast.class)) {
if (ice.prepared) {
ice.throwIce();
}
}
}
@Override
public void remove() {
super.remove();
if (progressing) {
if (source != null) {
source.revertBlock();
}
progressing = false;
}
if (player.isOnline()) {
if (bPlayer != null) {
bPlayer.addCooldown(this);
}
}
}
private void returnWater() {
new WaterReturn(player, sourceBlock);
}
private void affect(LivingEntity entity) {
if (entity instanceof Player) {
if (bPlayer.canBeSlowed()) {
PotionEffect effect = new PotionEffect(PotionEffectType.SLOW, 70, 2);
new TempPotionEffect(entity, effect);
bPlayer.slow(10);
DamageHandler.damageEntity(entity, damage, this);
}
} else {
PotionEffect effect = new PotionEffect(PotionEffectType.SLOW, 70, 2);
new TempPotionEffect(entity, effect);
DamageHandler.damageEntity(entity, damage, this);
}
AirAbility.breakBreathbendingHold(entity);
for (int x = 0; x < 30; x++) {
ParticleEffect.ITEM_CRACK.display(new ParticleEffect.ItemData(Material.ICE, (byte) 0), new Vector(((Math.random() - 0.5) * .5), ((Math.random() - 0.5) * .5), ((Math.random() - 0.5) * .5)), .3f, location, 255.0);
}
}
private void throwIce() {
if (!prepared) {
return;
}
LivingEntity target = (LivingEntity) GeneralMethods.getTargetedEntity(player, range, new ArrayList<Entity>());
if (target == null) {
destination = GeneralMethods.getTargetedLocation(player, range, getTransparentMaterials());
} else {
destination = target.getEyeLocation();
}
location = sourceBlock.getLocation();
if (destination.distanceSquared(location) < 1) {
return;
}
firstDestination = location.clone();
if (destination.getY() - location.getY() > 2) {
firstDestination.setY(destination.getY() - 1);
} else {
firstDestination.add(0, 2, 0);
}
destination = GeneralMethods.getPointOnLine(firstDestination, destination, range);
progressing = true;
settingUp = true;
prepared = false;
if (TempBlock.isTempBlock(sourceBlock)) {
TempBlock.get(sourceBlock).setType(Material.PACKED_ICE, data);
source = TempBlock.get(sourceBlock);
} else {
new TempBlock(sourceBlock, Material.AIR, (byte) 0);
source = new TempBlock(sourceBlock, Material.PACKED_ICE, data);
}
}
@Override
public void progress() {
if (!bPlayer.canBendIgnoreBinds(this)) {
remove();
return;
}
if (player.getEyeLocation().distanceSquared(location) >= range * range) {
if (progressing) {
breakParticles(20);
remove();
returnWater();
} else {
breakParticles(20);
remove();
}
return;
}
if (!bPlayer.getBoundAbilityName().equalsIgnoreCase(getName()) && prepared) {
remove();
return;
}
if (System.currentTimeMillis() < time + interval) {
return;
}
time = System.currentTimeMillis();
if (progressing) {
Vector direction;
if (location.getBlockY() == firstDestination.getBlockY()) {
settingUp = false;
}
if (location.distanceSquared(destination) <= 4) {
remove();
returnWater();
return;
}
if (settingUp) {
direction = GeneralMethods.getDirection(location, firstDestination).normalize();
} else {
direction = GeneralMethods.getDirection(location, destination).normalize();
}
location.add(direction);
Block block = location.getBlock();
if (block.equals(sourceBlock)) {
return;
}
source.revertBlock();
source = null;
if (isTransparent(player, block) && !block.isLiquid()) {
GeneralMethods.breakBlock(block);
} else if (!isWater(block)) {
breakParticles(20);
remove();
returnWater();
return;
}
if (GeneralMethods.isRegionProtectedFromBuild(this, location)) {
remove();
returnWater();
return;
}
for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, collisionRadius)) {
if (entity.getEntityId() != player.getEntityId() && entity instanceof LivingEntity) {
affect((LivingEntity) entity);
progressing = false;
returnWater();
}
}
if (!progressing) {
remove();
return;
}
sourceBlock = block;
if (TempBlock.isTempBlock(sourceBlock)) {
TempBlock.get(sourceBlock).setType(Material.PACKED_ICE, data);
source = TempBlock.get(sourceBlock);
} else {
source = new TempBlock(sourceBlock, Material.PACKED_ICE, data);
}
for (int x = 0; x < 10; x++) {
ParticleEffect.ITEM_CRACK.display(new ParticleEffect.ItemData(Material.ICE, (byte) 0), new Vector(((Math.random() - 0.5) * .5), ((Math.random() - 0.5) * .5), ((Math.random() - 0.5) * .5)), .5f, location, 255.0);
ParticleEffect.SNOW_SHOVEL.display(location, (float) (Math.random() - 0.5), (float) (Math.random() - 0.5), (float) (Math.random() - 0.5), 0, 5);
}
if ((new Random()).nextInt(4) == 0) {
playIcebendingSound(location);
}
location = location.add(direction.clone());
} else if (prepared) {
playFocusWaterEffect(sourceBlock);
}
}
public void breakParticles(int amount) {
for (int x = 0; x < amount; x++) {
ParticleEffect.ITEM_CRACK.display(new ParticleEffect.ItemData(Material.ICE, (byte) 0), new Vector(((Math.random() - 0.5) * .5), ((Math.random() - 0.5) * .5), ((Math.random() - 0.5) * .5)), 2f, location, 255.0);
ParticleEffect.SNOW_SHOVEL.display(location, (float) Math.random(), (float) Math.random(), (float) Math.random(), 0, 2);
}
location.getWorld().playSound(location, Sound.BLOCK_GLASS_BREAK, 5, 1.3f);
}
@Override
public String getName() {
return "IceBlast";
}
@Override
public Location getLocation() {
if (location != null) {
return location;
} else if (sourceBlock != null) {
return sourceBlock.getLocation();
}
return player != null ? player.getLocation() : null;
}
@Override
public long getCooldown() {
return cooldown;
}
@Override
public boolean isSneakAbility() {
return true;
}
@Override
public boolean isHarmlessAbility() {
return false;
}
@Override
public boolean isCollidable() {
return progressing;
}
@Override
public double getCollisionRadius() {
return collisionRadius;
}
public boolean isPrepared() {
return prepared;
}
public void setPrepared(boolean prepared) {
this.prepared = prepared;
}
public boolean isSettingUp() {
return settingUp;
}
public void setSettingUp(boolean settingUp) {
this.settingUp = settingUp;
}
public boolean isProgressing() {
return progressing;
}
public void setProgressing(boolean progressing) {
this.progressing = progressing;
}
public byte getData() {
return data;
}
public void setData(byte data) {
this.data = data;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public long getInterval() {
return interval;
}
public void setInterval(long interval) {
this.interval = interval;
}
public double getRange() {
return range;
}
public void setRange(double range) {
this.range = range;
}
public double getDamage() {
return damage;
}
public void setDamage(double damage) {
this.damage = damage;
}
public void setCollisionRadius(double collisionRadius) {
this.collisionRadius = collisionRadius;
}
public double getDeflectRange() {
return deflectRange;
}
public void setDeflectRange(double deflectRange) {
this.deflectRange = deflectRange;
}
public Block getSourceBlock() {
return sourceBlock;
}
public void setSourceBlock(Block sourceBlock) {
this.sourceBlock = sourceBlock;
}
public Location getFirstDestination() {
return firstDestination;
}
public void setFirstDestination(Location firstDestination) {
this.firstDestination = firstDestination;
}
public Location getDestination() {
return destination;
}
public void setDestination(Location destination) {
this.destination = destination;
}
public TempBlock getSource() {
return source;
}
public void setSource(TempBlock source) {
this.source = source;
}
public void setCooldown(long cooldown) {
this.cooldown = cooldown;
}
public void setLocation(Location location) {
this.location = location;
}
}