TF-ProjectKorra/src/com/projectkorra/projectkorra/earthbending/Ripple.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

444 lines
12 KiB
Java

package com.projectkorra.projectkorra.earthbending;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import com.projectkorra.projectkorra.GeneralMethods;
import com.projectkorra.projectkorra.ability.AirAbility;
import com.projectkorra.projectkorra.ability.EarthAbility;
import com.projectkorra.projectkorra.attribute.Attribute;
import com.projectkorra.projectkorra.avatar.AvatarState;
import com.projectkorra.projectkorra.command.Commands;
import com.projectkorra.projectkorra.util.DamageHandler;
public class Ripple extends EarthAbility {
private static final Map<Integer[], Block> BLOCKS = new ConcurrentHashMap<Integer[], Block>();
private int step;
private int maxStep;
@Attribute(Attribute.RANGE)
private double range;
@Attribute(Attribute.DAMAGE)
private double damage;
@Attribute(Attribute.KNOCKBACK)
private double knockback;
private Vector direction;
private Location origin;
private Location location;
private Block block1;
private Block block2;
private Block block3;
private Block block4;
private ArrayList<Location> locations = new ArrayList<Location>();
private ArrayList<Entity> entities = new ArrayList<Entity>();
public Ripple(final Player player, final Vector direction) {
super(player);
this.initialize(player, this.getInitialLocation(player, direction), direction);
}
public Ripple(final Player player, final Location origin, final Vector direction) {
super(player);
this.initialize(player, origin, direction);
}
private void initialize(final Player player, final Location origin, final Vector direction) {
if (origin == null) {
return;
}
this.range = getConfig().getDouble("Abilities.Earth.Shockwave.Range");
this.damage = getConfig().getDouble("Abilities.Earth.Shockwave.Damage");
this.knockback = getConfig().getDouble("Abilities.Earth.Shockwave.Knockback");
this.direction = direction.clone().normalize();
this.origin = origin.clone();
this.location = origin.clone();
this.locations = new ArrayList<>();
this.entities = new ArrayList<>();
if (this.bPlayer.isAvatarState()) {
this.range = getConfig().getDouble("Abilities.Avatar.AvatarState.Earth.Shockwave.Range");
this.damage = getConfig().getDouble("Abilities.Avatar.AvatarState.Earth.Shockwave.Damage");
this.knockback = getConfig().getDouble("Abilities.Avatar.AvatarState.Earth.Shockwave.Knockback");
}
this.initializeLocations();
this.maxStep = this.locations.size();
if (this.isEarthbendable(origin.getBlock())) {
this.start();
}
}
private Location getInitialLocation(final Player player, Vector direction) {
Location location = player.getLocation().clone().add(0, -1, 0);
direction = direction.normalize();
final Block block1 = location.getBlock();
while (location.getBlock().equals(block1)) {
location = location.clone().add(direction);
}
for (final int i : new int[] { 1, 2, 3, 0, -1 }) {
Location loc;
loc = location.clone().add(0, i, 0);
final Block topBlock = loc.getBlock();
final Block botBlock = loc.clone().add(0, -1, 0).getBlock();
if (this.isTransparent(topBlock) && this.isEarthbendable(botBlock)) {
location = loc.clone().add(0, -1, 0);
return location;
}
}
return null;
}
@Override
public void progress() {
if (this.step < this.maxStep) {
final Location newlocation = this.locations.get(this.step);
final Block block = this.location.getBlock();
this.location = newlocation.clone();
if (!newlocation.getBlock().equals(block)) {
this.block1 = this.block2;
this.block2 = this.block3;
this.block3 = this.block4;
this.block4 = newlocation.getBlock();
if (this.block1 != null) {
if (hasAnyMoved(this.block1)) {
this.block1 = null;
}
}
if (this.block2 != null) {
if (hasAnyMoved(this.block2)) {
this.block2 = null;
}
}
if (this.block3 != null) {
if (hasAnyMoved(this.block3)) {
this.block3 = null;
}
}
if (this.block4 != null) {
if (hasAnyMoved(this.block4)) {
this.block4 = null;
}
}
if (this.step == 0) {
if (this.increase(this.block4)) {
this.block4 = this.block4.getRelative(BlockFace.UP);
}
} else if (this.step == 1) {
if (this.increase(this.block3)) {
this.block3 = this.block3.getRelative(BlockFace.UP);
}
if (this.increase(this.block4)) {
this.block4 = this.block4.getRelative(BlockFace.UP);
}
} else if (this.step == 2) {
if (this.decrease(this.block2)) {
this.block2 = this.block2.getRelative(BlockFace.DOWN);
}
if (this.increase(this.block3)) {
this.block3 = this.block3.getRelative(BlockFace.UP);
}
if (this.increase(this.block4)) {
this.block4 = this.block4.getRelative(BlockFace.UP);
}
} else {
if (this.decrease(this.block1)) {
this.block1 = this.block1.getRelative(BlockFace.DOWN);
}
if (this.decrease(this.block2)) {
this.block2 = this.block2.getRelative(BlockFace.DOWN);
}
if (this.increase(this.block3)) {
this.block3 = this.block3.getRelative(BlockFace.UP);
}
if (this.increase(this.block4)) {
this.block4 = this.block4.getRelative(BlockFace.UP);
}
}
}
} else if (this.step == this.maxStep) {
if (this.decrease(this.block2)) {
this.block2 = this.block2.getRelative(BlockFace.DOWN);
}
if (this.decrease(this.block3)) {
this.block3 = this.block3.getRelative(BlockFace.DOWN);
}
if (this.increase(this.block4)) {
this.block4 = this.block4.getRelative(BlockFace.UP);
}
} else if (this.step == this.maxStep + 1) {
if (this.decrease(this.block3)) {
this.block3 = this.block3.getRelative(BlockFace.DOWN);
}
if (this.decrease(this.block4)) {
this.block4 = this.block4.getRelative(BlockFace.DOWN);
}
} else if (this.step == this.maxStep + 2) {
if (this.decrease(this.block4)) {
this.block4 = this.block4.getRelative(BlockFace.DOWN);
}
this.remove();
}
this.step += 1;
for (final Entity entity : this.entities) {
this.affect(entity);
}
this.entities.clear();
}
private void initializeLocations() {
Location location = this.origin.clone();
this.locations.add(location);
while (location.distanceSquared(this.origin) < this.range * this.range) {
location = location.clone().add(this.direction);
for (final int i : new int[] { 1, 2, 3, 0, -1 }) {
Location loc;
loc = location.clone().add(0, i, 0);
final Block topblock = loc.getBlock();
final Block botblock = loc.clone().add(0, -1, 0).getBlock();
if (this.isTransparent(topblock) && !topblock.isLiquid() && this.isEarthbendable(botblock)) {
location = loc.clone().add(0, -1, 0);
this.locations.add(location);
break;
} else if (i == -1) {
return;
}
}
}
}
private boolean decrease(Block block) {
if (block == null) {
return false;
} else if (hasAnyMoved(block)) {
return false;
}
setMoved(block);
final Block botBlock = block.getRelative(BlockFace.DOWN);
int length = 1;
if (this.isEarthbendable(botBlock)) {
length = 2;
block = botBlock;
}
return this.moveEarth(block, new Vector(0, -1, 0), length, false);
}
private boolean increase(final Block block) {
if (block == null) {
return false;
} else if (hasAnyMoved(block)) {
return false;
}
setMoved(block);
final Block botblock = block.getRelative(BlockFace.DOWN);
int length = 1;
if (this.isEarthbendable(botblock)) {
length = 2;
}
if (this.moveEarth(block, new Vector(0, 1, 0), length, false)) {
for (final Entity entity : GeneralMethods.getEntitiesAroundPoint(block.getLocation().clone().add(0, 1, 0), 2)) {
if (entity.getEntityId() != this.player.getEntityId() && !this.entities.contains(entity)) {
if (!(entity instanceof FallingBlock)) {
this.entities.add(entity);
}
}
}
return true;
}
return false;
}
private void affect(final Entity entity) {
if (GeneralMethods.isRegionProtectedFromBuild(this, entity.getLocation()) || ((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))) {
return;
}
if (entity instanceof LivingEntity) {
DamageHandler.damageEntity(entity, this.damage, this);
}
final Vector vector = this.direction.clone();
vector.setY(.5);
final double knock = this.bPlayer.isAvatarState() ? AvatarState.getValue(this.knockback) : this.knockback;
GeneralMethods.setVelocity(this, entity, vector.clone().normalize().multiply(knock));
AirAbility.breakBreathbendingHold(entity);
}
private static void setMoved(final Block block) {
final int x = block.getX();
final int z = block.getZ();
final Integer[] pair = new Integer[] { x, z };
BLOCKS.put(pair, block);
}
private static boolean hasAnyMoved(final Block block) {
final int x = block.getX();
final int z = block.getZ();
final Integer[] pair = new Integer[] { x, z };
if (BLOCKS.containsKey(pair)) {
return true;
}
return false;
}
public static void progressAllCleanup() {
BLOCKS.clear();
}
public static Map<Integer[], Block> getBlocks() {
return BLOCKS;
}
@Override
public String getName() {
return "Shockwave";
}
@Override
public Location getLocation() {
return this.location;
}
@Override
public long getCooldown() {
return 0;
}
@Override
public boolean isSneakAbility() {
return true;
}
@Override
public boolean isHarmlessAbility() {
return false;
}
@Override
public ArrayList<Location> getLocations() {
return this.locations;
}
public int getStep() {
return this.step;
}
public void setStep(final int step) {
this.step = step;
}
public int getMaxStep() {
return this.maxStep;
}
public void setMaxStep(final int maxStep) {
this.maxStep = maxStep;
}
public double getRange() {
return this.range;
}
public void setRange(final double range) {
this.range = range;
}
public double getDamage() {
return this.damage;
}
public void setDamage(final double damage) {
this.damage = damage;
}
public double getKnockback() {
return this.knockback;
}
public void setKnockback(final double knockback) {
this.knockback = knockback;
}
public Vector getDirection() {
return this.direction;
}
public void setDirection(final Vector direction) {
this.direction = direction;
}
public Location getOrigin() {
return this.origin;
}
public void setOrigin(final Location origin) {
this.origin = origin;
}
public Block getBlock1() {
return this.block1;
}
public void setBlock1(final Block block1) {
this.block1 = block1;
}
public Block getBlock2() {
return this.block2;
}
public void setBlock2(final Block block2) {
this.block2 = block2;
}
public Block getBlock3() {
return this.block3;
}
public void setBlock3(final Block block3) {
this.block3 = block3;
}
public Block getBlock4() {
return this.block4;
}
public void setBlock4(final Block block4) {
this.block4 = block4;
}
public ArrayList<Entity> getEntities() {
return this.entities;
}
public void setLocation(final Location location) {
this.location = location;
}
}