mirror of
https://github.com/TotalFreedomMC/TF-ProjectKorra.git
synced 2024-05-15 17:31:26 +00:00
0b35fb9fda
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.
455 lines
12 KiB
Java
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;
|
|
}
|
|
|
|
}
|