TF-ProjectKorra/src/com/projectkorra/projectkorra/waterbending/ice/IceSpikePillar.java
dniym 0b35fb9fda
Add AbilityVelocityAffectEntityEvent (#1094)
Created a cancellable event that will fire whenever a bending move would
alter the velocity of an entity.

## Additions
* Adds 1.
    > The AbilityVelocityAffectEntityEvent
    > Adds a new method to GeneralMethods -> setEntityVelocity()
    > Updates existing setVelocity() calls to use the new method in general methods.
    > checks to see if anything in the event should be modified or if it should be cancelled.

## Fixes
* Fixes 2
    > The lack of a way to detect when a bending move pushed a player.
2020-10-17 17:27:44 -07:00

455 lines
12 KiB
Java

package com.projectkorra.projectkorra.waterbending.ice;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import com.projectkorra.projectkorra.GeneralMethods;
import com.projectkorra.projectkorra.ability.AirAbility;
import com.projectkorra.projectkorra.ability.ElementalAbility;
import com.projectkorra.projectkorra.ability.IceAbility;
import com.projectkorra.projectkorra.ability.WaterAbility;
import com.projectkorra.projectkorra.attribute.Attribute;
import com.projectkorra.projectkorra.util.DamageHandler;
import com.projectkorra.projectkorra.util.TempBlock;
import com.projectkorra.projectkorra.util.TempPotionEffect;
public class IceSpikePillar extends IceAbility {
/** The list of blocks IceSpike uses */
private final Map<Block, TempBlock> ice_blocks = new HashMap<Block, TempBlock>();
@Attribute(Attribute.HEIGHT)
private int height;
private int progress;
@Attribute("SlowPotency")
private int slowPower;
@Attribute("Slow" + Attribute.DURATION)
private int slowDuration;
@Attribute(Attribute.COOLDOWN)
private long cooldown;
private long time;
private long removeTimestamp;
@Attribute(Attribute.DURATION)
private long duration;
private long interval;
@Attribute("Slow" + Attribute.COOLDOWN)
private long slowCooldown;
@Attribute(Attribute.DAMAGE)
private double damage;
@Attribute(Attribute.RANGE)
private double range;
@Attribute(Attribute.SPEED)
private double speed;
private Block source_block; // The block clicked on.
private Block base_block; // The block at the bottom of the pillar.
private Location origin;
private Location location;
private Vector thrownForce;
private Vector direction;
private ArrayList<LivingEntity> damaged;
protected boolean inField = false; // If it's part of a field or not.
public IceSpikePillar(final Player player) {
super(player);
this.setFields();
if (this.bPlayer.isOnCooldown("IceSpikePillar")) {
return;
}
try {
double lowestDistance = this.range + 1;
Entity closestEntity = null;
for (final Entity entity : GeneralMethods.getEntitiesAroundPoint(player.getLocation(), this.range)) {
if (GeneralMethods.getDistanceFromLine(player.getLocation().getDirection(), player.getLocation(), entity.getLocation()) <= 2 && (entity instanceof LivingEntity) && (entity.getEntityId() != player.getEntityId())) {
double distance = 0;
if (player.getWorld().equals(entity.getWorld())) {
distance = player.getLocation().distance(entity.getLocation());
}
if (distance < lowestDistance) {
closestEntity = entity;
lowestDistance = distance;
}
}
}
if (closestEntity != null) {
final Block tempTestingBlock = closestEntity.getLocation().getBlock().getRelative(BlockFace.DOWN, 1);
this.source_block = tempTestingBlock;
} else {
this.source_block = WaterAbility.getIceSourceBlock(player, this.range);
if (this.source_block == null) {
return;
}
}
this.origin = this.source_block.getLocation();
this.location = this.origin.clone();
} catch (final IllegalStateException e) {
return;
}
if (this.height != 0) {
if (this.canInstantiate()) {
this.start();
this.time = System.currentTimeMillis() - this.interval;
this.bPlayer.addCooldown("IceSpikePillar", this.cooldown);
}
}
}
public IceSpikePillar(final Player player, final Location origin, final int damage, final Vector throwing, final long aoecooldown) {
super(player);
this.setFields();
this.cooldown = aoecooldown;
this.player = player;
this.origin = origin;
this.damage = damage;
this.thrownForce = throwing;
this.location = origin.clone();
this.source_block = this.location.getBlock();
if (this.isIcebendable(this.source_block)) {
if (this.canInstantiate()) {
this.start();
this.time = System.currentTimeMillis() - this.interval;
}
}
}
private void setFields() {
this.direction = new Vector(0, 1, 0);
this.speed = getConfig().getDouble("Abilities.Water.IceSpike.Speed");
this.slowCooldown = getConfig().getLong("Abilities.Water.IceSpike.SlowCooldown");
this.slowPower = getConfig().getInt("Abilities.Water.IceSpike.SlowPower");
this.slowDuration = getConfig().getInt("Abilities.Water.IceSpike.SlowDuration");
this.damage = getConfig().getDouble("Abilities.Water.IceSpike.Damage");
this.range = getConfig().getDouble("Abilities.Water.IceSpike.Range");
this.cooldown = getConfig().getLong("Abilities.Water.IceSpike.Cooldown");
this.height = getConfig().getInt("Abilities.Water.IceSpike.Height");
this.thrownForce = new Vector(0, getConfig().getDouble("Abilities.Water.IceSpike.Push"), 0);
this.damaged = new ArrayList<>();
this.interval = (long) (1000. / this.speed);
if (this.bPlayer.isAvatarState()) {
this.slowPower = getConfig().getInt("Abilities.Avatar.AvatarState.Water.IceSpike.SlowPower");
this.slowDuration = getConfig().getInt("Abilities.Avatar.AvatarState.Water.IceSpike.SlowDuration");
this.damage = getConfig().getDouble("Abilities.Avatar.AvatarState.Water.IceSpike.Damage");
this.range = getConfig().getDouble("Abilities.Avatar.AvatarState.Water.IceSpike.Range");
this.height = getConfig().getInt("Abilities.Avatar.AvatarState.Water.IceSpike.Height");
this.thrownForce = new Vector(0, getConfig().getDouble("Abilities.Avatar.AvatarState.Water.IceSpike.Push"), 0);
}
}
/**
* Reverts the block if it's part of IceSpike
*
* @param block The Block
* @return If the block was removed or not
*/
public static boolean revertBlock(final Block block) {
for (final IceSpikePillar iceSpike : getAbilities(IceSpikePillar.class)) {
if (iceSpike.ice_blocks.containsKey(block)) {
iceSpike.ice_blocks.get(block).revertBlock();
iceSpike.ice_blocks.remove(block);
return true;
}
}
return false;
}
/**
* Checks to see if this move can start. Checks things like if there is
* enough space to form, if the source isn't a TempBlock, etc.
*/
private boolean canInstantiate() {
if (!this.isIcebendable(this.source_block.getType())) {
return false;
}
Block b;
for (int i = 1; i <= this.height; i++) {
b = this.source_block.getWorld().getBlockAt(this.location.clone().add(this.direction.clone().multiply(i)));
if (!ElementalAbility.isAir(b.getType())) {
return false;
}
if (b.getX() == this.player.getEyeLocation().getBlock().getX() && b.getZ() == this.player.getEyeLocation().getBlock().getZ()) {
return false;
}
}
return true;
}
@Override
public void progress() {
if (System.currentTimeMillis() - this.time >= this.interval) {
this.time = System.currentTimeMillis();
if (this.progress < this.height) {
this.risePillar();
this.removeTimestamp = System.currentTimeMillis();
} else {
// If it's time to remove.
if (this.removeTimestamp != 0 && this.removeTimestamp + this.duration <= System.currentTimeMillis()) {
if (!this.sinkPillar()) {
this.remove();
return;
}
}
}
}
}
/**
* Makes the pillar rise by 1 block.
*
* @return If the block was placed successfully.
*/
private boolean risePillar() {
this.progress++;
final Block affectedBlock = this.location.clone().add(this.direction).getBlock();
this.location = this.location.add(this.direction);
if (GeneralMethods.isRegionProtectedFromBuild(this, this.location)) {
return false;
}
for (final Entity en : GeneralMethods.getEntitiesAroundPoint(this.location, 1.4)) {
if (en instanceof LivingEntity && en != this.player && !this.damaged.contains((en))) {
final LivingEntity le = (LivingEntity) en;
this.affect(le);
}
}
final TempBlock b = new TempBlock(affectedBlock, Material.ICE);
this.ice_blocks.put(affectedBlock, b);
if (!this.inField || new Random().nextInt((int) ((this.height + 1) * 1.5)) == 0) {
playIcebendingSound(this.source_block.getLocation());
}
return true;
}
private void affect(final LivingEntity entity) {
GeneralMethods.setVelocity(this, entity, this.thrownForce);
DamageHandler.damageEntity(entity, this.damage, this);
this.damaged.add(entity);
if (entity instanceof Player) {
if (this.bPlayer.canBeSlowed()) {
final PotionEffect effect = new PotionEffect(PotionEffectType.SLOW, this.slowDuration, this.slowPower);
new TempPotionEffect(entity, effect);
this.bPlayer.slow(this.slowCooldown);
}
} else {
final PotionEffect effect = new PotionEffect(PotionEffectType.SLOW, this.slowDuration, this.slowPower);
new TempPotionEffect(entity, effect);
}
AirAbility.breakBreathbendingHold(entity);
}
/**
* The reverse of risePillar(). Makes the pillar sink
*
* @return If the move should continue progressing.
*/
public boolean sinkPillar() {
final Vector direction = this.direction.clone().multiply(-1);
if (this.ice_blocks.containsKey(this.location.getBlock())) {
this.ice_blocks.get(this.location.getBlock()).revertBlock();
this.ice_blocks.remove(this.location.getBlock());
this.location.add(direction);
if (this.source_block.equals(this.location.getBlock())) {
return false;
}
}
return true;
}
@Override
public String getName() {
return "IceSpike";
}
@Override
public boolean isSneakAbility() {
return true;
}
@Override
public boolean isHarmlessAbility() {
return false;
}
public int getHeight() {
return this.height;
}
public void setHeight(final int height) {
this.height = height;
}
public int getProgress() {
return this.progress;
}
public void setProgress(final int progress) {
this.progress = progress;
}
public int getSlowPower() {
return this.slowPower;
}
public void setSlowPower(final int slowPower) {
this.slowPower = slowPower;
}
public int getSlowDuration() {
return this.slowDuration;
}
public void setSlowDuration(final int slowDuration) {
this.slowDuration = slowDuration;
}
@Override
public long getCooldown() {
return this.cooldown;
}
public void setCooldown(final long cooldown) {
this.cooldown = cooldown;
}
public long getTime() {
return this.time;
}
public void setTime(final long time) {
this.time = time;
}
public long getRemoveTimestamp() {
return this.removeTimestamp;
}
public void setRemoveTimestamp(final long removeTimestamp) {
this.removeTimestamp = removeTimestamp;
}
public long getDuration() {
return this.duration;
}
public void setDuration(final long duration) {
this.duration = duration;
}
public long getInterval() {
return this.interval;
}
public void setInterval(final long interval) {
this.interval = interval;
}
public long getSlowCooldown() {
return this.slowCooldown;
}
public void setSlowCooldown(final long slowCooldown) {
this.slowCooldown = slowCooldown;
}
public double getDamage() {
return this.damage;
}
public void setDamage(final double damage) {
this.damage = damage;
}
public double getRange() {
return this.range;
}
public void setRange(final double range) {
this.range = range;
}
public double getSpeed() {
return this.speed;
}
public void setSpeed(final double speed) {
this.speed = speed;
}
public Block getBlock() {
return this.source_block;
}
public void setBlock(final Block block) {
this.source_block = block;
}
public Location getOrigin() {
return this.origin;
}
public void setOrigin(final Location origin) {
this.origin = origin;
}
@Override
public Location getLocation() {
return this.location;
}
public void setLocation(final Location location) {
this.location = location;
}
public Vector getThrownForce() {
return this.thrownForce;
}
public void setThrownForce(final Vector thrownForce) {
this.thrownForce = thrownForce;
}
public Vector getDirection() {
return this.direction;
}
public void setDirection(final Vector direction) {
this.direction = direction;
}
public Map<Block, TempBlock> getIceBlocks() {
return this.ice_blocks;
}
public Block getBaseBlock() {
return this.base_block;
}
}