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

679 lines
22 KiB
Java

package com.projectkorra.projectkorra.earthbending.metal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.Zombie;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import com.projectkorra.projectkorra.command.Commands;
import com.projectkorra.projectkorra.GeneralMethods;
import com.projectkorra.projectkorra.ability.CoreAbility;
import com.projectkorra.projectkorra.ability.MetalAbility;
import com.projectkorra.projectkorra.attribute.Attribute;
import com.projectkorra.projectkorra.util.DamageHandler;
import com.projectkorra.projectkorra.util.TempArmor;
public class MetalClips extends MetalAbility {
private static final Map<Entity, Integer> ENTITY_CLIPS_COUNT = new ConcurrentHashMap<>();
private static final Map<Entity, MetalClips> TARGET_TO_ABILITY = new ConcurrentHashMap<>();
private static final Material[] METAL_ITEMS = { Material.IRON_INGOT, Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS, Material.IRON_BLOCK, Material.IRON_AXE, Material.IRON_PICKAXE, Material.IRON_SWORD, Material.IRON_HOE, Material.IRON_SHOVEL, Material.IRON_DOOR };
private boolean isBeingWorn;
private boolean isControlling;
@Attribute("CanThrow")
private boolean canThrow;
private boolean isMagnetized;
@Attribute("CanUse4Clips")
private boolean canUse4Clips;
@Attribute("CanLoot")
private boolean canLoot;
private boolean hasSnuck;
private int metalClipsCount;
private int abilityType;
private int armorTime;
@Attribute("Magnet" + Attribute.RANGE)
private int magnetRange;
private long armorStartTime;
@Attribute(Attribute.COOLDOWN)
private long cooldown;
@Attribute("Shoot" + Attribute.COOLDOWN)
private long shootCooldown;
@Attribute("Crush" + Attribute.COOLDOWN)
private long crushCooldown;
@Attribute("Magnet" + Attribute.COOLDOWN)
private long magnetCooldown;
@Attribute("Magnet" + Attribute.SPEED)
private double magnetSpeed;
@Attribute(Attribute.RANGE)
private double range;
@Attribute("Crush" + Attribute.DAMAGE)
private double crushDamage;
@Attribute(Attribute.DAMAGE)
private double damage;
private LivingEntity targetEntity;
private List<Item> trackedIngots;
public MetalClips(final Player player, final int abilityType) {
super(player);
if (hasAbility(player, MetalClips.class)) {
return;
}
this.abilityType = abilityType;
this.canLoot = player.hasPermission("bending.ability.MetalClips.loot");
this.canUse4Clips = player.hasPermission("bending.ability.MetalClips.4clips");
this.armorTime = getConfig().getInt("Abilities.Earth.MetalClips.Duration");
this.range = getConfig().getDouble("Abilities.Earth.MetalClips.Range");
this.cooldown = getConfig().getLong("Abilities.Earth.MetalClips.Cooldown");
this.shootCooldown = 600;
this.crushCooldown = getConfig().getLong("Abilities.Earth.MetalClips.Crush.Cooldown");
this.magnetCooldown = getConfig().getLong("Abilities.Earth.MetalClips.Magnet.Cooldown");
this.magnetRange = getConfig().getInt("Abilities.Earth.MetalClips.Magnet.Range");
this.magnetSpeed = getConfig().getDouble("Abilities.Earth.MetalClips.Magnet.Speed");
this.crushDamage = getConfig().getDouble("Abilities.Earth.MetalClips.Crush.Damage");
this.damage = getConfig().getDouble("Abilities.Earth.MetalClips.Damage");
this.canThrow = (getConfig().getBoolean("Abilities.Earth.MetalClips.ThrowEnabled") && player.hasPermission("bending.ability.metalclips.throw"));
this.trackedIngots = new ArrayList<>();
if (this.bPlayer.isAvatarState()) {
this.cooldown = getConfig().getLong("Abilities.Avatar.AvatarState.Earth.MetalClips.Cooldown");
this.range = getConfig().getDouble("Abilities.Avatar.AvatarState.Earth.MetalClips.Range");
this.crushDamage = getConfig().getLong("Abilities.Avatar.AvatarState.Earth.MetalClips.CrushDamage");
}
if (abilityType == 0) {
if (!this.bPlayer.canBend(this)) {
return;
}
if (!player.getInventory().containsAtLeast(new ItemStack(Material.IRON_INGOT), 1)) {
return;
}
this.shootMetal();
} else if (abilityType == 1) {
if (this.bPlayer.isOnCooldown("MetalClips Magnet")) {
return;
}
this.isMagnetized = true;
}
this.start();
}
/*
* public static ItemStack getOriginalHelmet(LivingEntity ent) { MetalClips
* clips = TARGET_TO_ABILITY.get(ent); if (clips != null) { return
* clips.oldArmor[3]; } return null; }
*
* public static ItemStack getOriginalChestplate(LivingEntity ent) {
* MetalClips clips = TARGET_TO_ABILITY.get(ent); if (clips != null) {
* return clips.oldArmor[2]; } return null; }
*
* public static ItemStack getOriginalLeggings(LivingEntity ent) {
* MetalClips clips = TARGET_TO_ABILITY.get(ent); if (clips != null) {
* return clips.oldArmor[1]; } return null; }
*
* public static ItemStack getOriginalBoots(LivingEntity ent) { MetalClips
* clips = TARGET_TO_ABILITY.get(ent); if (clips != null) { return
* clips.oldArmor[0]; } return null; }
*
* public static ItemStack[] getOriginalArmor(LivingEntity ent) { MetalClips
* clips = TARGET_TO_ABILITY.get(ent); if (clips != null) { return
* clips.oldArmor; } return null; }
*/
public void shootMetal() {
if (this.bPlayer.isOnCooldown("MetalClips Shoot")) {
return;
}
this.bPlayer.addCooldown("MetalClips Shoot", this.shootCooldown);
final ItemStack is = new ItemStack(Material.IRON_INGOT, 1);
if (!this.player.getInventory().containsAtLeast(is, 1)) {
return;
}
final Item item = this.player.getWorld().dropItemNaturally(this.player.getLocation().add(0, 1, 0), is);
Vector vector;
final Entity targetedEntity = GeneralMethods.getTargetedEntity(this.player, this.range, new ArrayList<Entity>());
if (targetedEntity != null) {
vector = GeneralMethods.getDirection(this.player.getLocation(), targetedEntity.getLocation());
} else {
vector = GeneralMethods.getDirection(this.player.getLocation(), GeneralMethods.getTargetedLocation(this.player, this.range));
}
GeneralMethods.setVelocity(this, item, vector.normalize().add(new Vector(0, 0.1, 0).multiply(1.2)));
this.trackedIngots.add(item);
this.player.getInventory().removeItem(is);
}
public void formArmor() {
if (this.metalClipsCount >= 4) {
return;
} else if (this.metalClipsCount == 3 && !this.canUse4Clips) {
return;
} else if (this.targetEntity != null && (GeneralMethods.isRegionProtectedFromBuild(this, this.targetEntity.getLocation()) || ((targetEntity instanceof Player) && Commands.invincible.contains(((Player) targetEntity).getName())))) {
return;
}
this.metalClipsCount = (this.metalClipsCount < 4) ? this.metalClipsCount + 1 : 4;
if (this.targetEntity instanceof Player) {
final Player target = (Player) this.targetEntity;
final ItemStack[] metalArmor = new ItemStack[4];
metalArmor[2] = (this.metalClipsCount >= 1) ? new ItemStack(Material.IRON_CHESTPLATE) : null;
metalArmor[0] = (this.metalClipsCount >= 2) ? new ItemStack(Material.IRON_BOOTS) : null;
metalArmor[1] = (this.metalClipsCount >= 3) ? new ItemStack(Material.IRON_LEGGINGS) : null;
metalArmor[3] = (this.metalClipsCount >= 4) ? new ItemStack(Material.IRON_HELMET) : null;
ENTITY_CLIPS_COUNT.put(target, this.metalClipsCount);
new TempArmor(target, this, metalArmor);
} else {
final ItemStack[] metalarmor = new ItemStack[4];
metalarmor[2] = (this.metalClipsCount >= 1) ? new ItemStack(Material.IRON_CHESTPLATE) : null;
metalarmor[0] = (this.metalClipsCount >= 2) ? new ItemStack(Material.IRON_BOOTS) : null;
metalarmor[1] = (this.metalClipsCount >= 3) ? new ItemStack(Material.IRON_LEGGINGS) : null;
metalarmor[3] = (this.metalClipsCount >= 4) ? new ItemStack(Material.IRON_HELMET) : null;
ENTITY_CLIPS_COUNT.put(this.targetEntity, this.metalClipsCount);
new TempArmor(this.targetEntity, this, metalarmor);
}
this.armorStartTime = System.currentTimeMillis();
this.isBeingWorn = true;
}
public void resetArmor() {
if (this.targetEntity == null || !TempArmor.hasTempArmor(this.targetEntity) || this.targetEntity.isDead()) {
return;
}
for (final TempArmor tarmor : TempArmor.getTempArmorList(targetEntity)) {
tarmor.revert();
}
this.dropIngots(this.targetEntity.getLocation());
this.isBeingWorn = false;
}
public void launch() {
if (!this.canThrow) {
return;
}
if (this.targetEntity == null) {
return;
}
final Location location = this.player.getLocation();
double dx, dy, dz;
final Location target = this.targetEntity.getLocation().clone();
dx = target.getX() - location.getX();
dy = target.getY() - location.getY();
dz = target.getZ() - location.getZ();
final Vector vector = new Vector(dx, dy, dz);
vector.normalize();
GeneralMethods.setVelocity(this, this.targetEntity, vector.multiply(this.metalClipsCount / 2D));
this.remove();
}
public void crush() {
if (this.bPlayer.isOnCooldown("MetalClips Crush")) {
return;
}
this.bPlayer.addCooldown("MetalClips Crush", this.crushCooldown);
DamageHandler.damageEntity(this.targetEntity, this.player, this.crushDamage, this);
}
@Override
public void progress() {
if (!this.bPlayer.canBendIgnoreCooldowns(this)) {
this.remove();
return;
}
if (this.targetEntity != null) {
if ((this.targetEntity instanceof Player && !((Player) this.targetEntity).isOnline()) || this.targetEntity.isDead()) {
this.remove();
return;
}
}
if (this.player.isSneaking()) {
this.hasSnuck = true;
}
if (!this.player.isSneaking()) {
if (this.isMagnetized) {
this.bPlayer.addCooldown("MetalClips Magnet", this.magnetCooldown);
this.remove();
return;
}
this.isControlling = false;
this.isMagnetized = false;
if (this.metalClipsCount > 0 && this.hasSnuck && this.abilityType == 0) {
this.launch();
}
}
if (this.isMagnetized) {
if (GeneralMethods.getEntitiesAroundPoint(this.player.getLocation(), this.magnetRange).size() == 0) {
this.remove();
return;
}
for (final Entity entity : GeneralMethods.getEntitiesAroundPoint(this.player.getLocation(), this.magnetRange)) {
final Vector vector = GeneralMethods.getDirection(entity.getLocation(), this.player.getLocation());
final ItemStack itemInHand = this.player.getInventory().getItemInMainHand();
if (entity instanceof Player && this.canLoot && itemInHand.getType() == Material.IRON_INGOT && (itemInHand.hasItemMeta() && itemInHand.getItemMeta().getDisplayName().equalsIgnoreCase("Magnet"))) {
final Player targetPlayer = (Player) entity;
if (targetPlayer.getEntityId() == this.player.getEntityId()) {
continue;
}
final ItemStack[] inventory = targetPlayer.getInventory().getContents();
for (final ItemStack is : inventory) {
if (is == null) {
continue;
}
if (Arrays.asList(METAL_ITEMS).contains(is.getType())) {
targetPlayer.getWorld().dropItem(targetPlayer.getLocation(), is);
is.setType(Material.AIR);
is.setAmount(0);
}
}
targetPlayer.getInventory().setContents(inventory);
final ItemStack[] armor = targetPlayer.getInventory().getArmorContents();
for (final ItemStack is : armor) {
if (Arrays.asList(METAL_ITEMS).contains(is.getType())) {
targetPlayer.getWorld().dropItem(targetPlayer.getLocation(), is);
is.setType(Material.AIR);
}
}
targetPlayer.getInventory().setArmorContents(armor);
if (Arrays.asList(METAL_ITEMS).contains(targetPlayer.getInventory().getItemInMainHand().getType())) {
targetPlayer.getWorld().dropItem(targetPlayer.getLocation(), targetPlayer.getEquipment().getItemInMainHand());
targetPlayer.getEquipment().setItemInMainHand(new ItemStack(Material.AIR, 1));
}
}
if ((entity instanceof Zombie || entity instanceof Skeleton) && this.canLoot && itemInHand.getType() == Material.IRON_INGOT && itemInHand.getItemMeta().getDisplayName().equalsIgnoreCase("Magnet")) {
final LivingEntity livingEntity = (LivingEntity) entity;
final ItemStack[] armor = livingEntity.getEquipment().getArmorContents();
for (final ItemStack istack : armor) {
if (Arrays.asList(METAL_ITEMS).contains(istack.getType())) {
livingEntity.getWorld().dropItem(livingEntity.getLocation(), istack);
istack.setType(Material.AIR);
}
}
livingEntity.getEquipment().setArmorContents(armor);
if (Arrays.asList(METAL_ITEMS).contains(livingEntity.getEquipment().getItemInMainHand().getType())) {
livingEntity.getWorld().dropItem(livingEntity.getLocation(), livingEntity.getEquipment().getItemInMainHand());
livingEntity.getEquipment().setItemInMainHand(new ItemStack(Material.AIR, 1));
}
}
if (entity instanceof Item) {
final Item iron = (Item) entity;
if (Arrays.asList(METAL_ITEMS).contains(iron.getItemStack().getType())) {
GeneralMethods.setVelocity(this, iron, vector.normalize().multiply(this.magnetSpeed).add(new Vector(0, 0.2, 0)));
}
}
}
}
if (this.isBeingWorn && System.currentTimeMillis() > this.armorStartTime + this.armorTime) {
this.remove();
return;
}
if (this.isControlling && this.player.isSneaking()) {
if (this.metalClipsCount == 1) {
final Location oldLocation = this.targetEntity.getLocation();
Location loc = oldLocation;
if (this.player.getWorld().equals(oldLocation.getWorld())) {
loc = GeneralMethods.getTargetedLocation(this.player, (int) this.player.getLocation().distance(oldLocation));
}
double distance = 0;
if (loc.getWorld().equals(oldLocation.getWorld())) {
distance = loc.distance(oldLocation);
}
final Vector vector = GeneralMethods.getDirection(this.targetEntity.getLocation(), this.player.getLocation());
if (distance > 0.5) {
GeneralMethods.setVelocity(this, this.targetEntity, vector.normalize().multiply(0.2));
}
}
if (this.metalClipsCount == 2) {
final Location oldLocation = this.targetEntity.getLocation();
Location loc = oldLocation;
if (this.player.getWorld().equals(oldLocation.getWorld())) {
loc = GeneralMethods.getTargetedLocation(this.player, (int) this.player.getLocation().distance(oldLocation));
}
double distance = 0;
if (loc.getWorld().equals(oldLocation.getWorld())) {
distance = loc.distance(oldLocation);
}
final Vector vector = GeneralMethods.getDirection(this.targetEntity.getLocation(), GeneralMethods.getTargetedLocation(this.player, 10));
if (distance > 1.2) {
GeneralMethods.setVelocity(this, this.targetEntity, vector.normalize().multiply(0.2));
}
}
if (this.metalClipsCount >= 3) {
final Location oldLocation = this.targetEntity.getLocation();
Location loc = oldLocation;
if (this.player.getWorld().equals(oldLocation.getWorld())) {
loc = GeneralMethods.getTargetedLocation(this.player, (int) this.player.getLocation().distance(oldLocation));
}
double distance = 0;
if (loc.getWorld().equals(oldLocation.getWorld())) {
distance = loc.distance(oldLocation);
}
final Vector vector = GeneralMethods.getDirection(oldLocation, GeneralMethods.getTargetedLocation(this.player, 10));
if (distance > 1.2) {
GeneralMethods.setVelocity(this, this.targetEntity, vector.normalize().multiply(.5));
} else {
GeneralMethods.setVelocity(this, this.targetEntity, new Vector(0, 0, 0));
}
this.targetEntity.setFallDistance(0);
}
}
final Iterator<Item> it = this.trackedIngots.iterator();
while (it.hasNext()) {
final Item ii = it.next();
if (ii.isOnGround()) {
it.remove();
continue;
}
for (final Entity e : GeneralMethods.getEntitiesAroundPoint(ii.getLocation(), 1.8)) {
if (e instanceof LivingEntity && e.getEntityId() != this.player.getEntityId()) {
if ((e instanceof Player || e instanceof Zombie || e instanceof Skeleton)) {
if (this.targetEntity == null) {
this.targetEntity = (LivingEntity) e;
TARGET_TO_ABILITY.put(this.targetEntity, this);
this.formArmor();
} else if (this.targetEntity == e) {
this.formArmor();
} else {
if (TARGET_TO_ABILITY.get(this.targetEntity) == this) {
this.resetArmor();
this.metalClipsCount = 0;
ENTITY_CLIPS_COUNT.remove(this.targetEntity);
TARGET_TO_ABILITY.remove(this.targetEntity);
this.targetEntity = (LivingEntity) e;
TARGET_TO_ABILITY.put(this.targetEntity, this);
this.formArmor();
} else {
TARGET_TO_ABILITY.get(this.targetEntity).remove();
}
}
} else {
DamageHandler.damageEntity(e, this.player, this.damage, this);
this.dropIngots(e.getLocation(), ii.getItemStack().getAmount());
}
it.remove();
ii.remove();
break;
}
}
}
}
public void dropIngots(final Location loc) {
this.dropIngots(loc, this.metalClipsCount == 0 ? 1 : this.metalClipsCount);
}
public void dropIngots(final Location loc, final int amount) {
final Item i = this.player.getWorld().dropItem(loc, new ItemStack(Material.IRON_INGOT, amount));
i.setPickupDelay(61);
}
@Override
public void remove() {
super.remove();
this.resetArmor();
if (!this.isMagnetized) {
this.bPlayer.addCooldown(this);
}
this.trackedIngots.clear();
this.metalClipsCount = 0;
if (this.targetEntity != null) {
ENTITY_CLIPS_COUNT.remove(this.targetEntity);
TARGET_TO_ABILITY.remove(this.targetEntity);
}
}
public static boolean isControlled(final LivingEntity player) {
return TARGET_TO_ABILITY.containsKey(player);
}
public static boolean isControllingEntity(final Player player) {
final MetalClips clips = getAbility(player, MetalClips.class);
return clips != null && player.isSneaking() && clips.targetEntity != null;
}
public static Map<Entity, Integer> getEntityClipsCount() {
return ENTITY_CLIPS_COUNT;
}
public static Map<Entity, MetalClips> getTargetToAbility() {
return TARGET_TO_ABILITY;
}
public static boolean removeControlledEnitity(final LivingEntity entity) {
if (entity == null) {
return false;
}
for (final MetalClips metalclips : CoreAbility.getAbilities(MetalClips.class)) {
if (metalclips.targetEntity == entity) {
metalclips.remove();
return true;
}
}
return false;
}
@Override
public String getName() {
return "MetalClips";
}
@Override
public Location getLocation() {
if (this.targetEntity != null) {
return this.targetEntity.getLocation();
} else if (this.player != null) {
return this.player.getLocation();
}
return null;
}
@Override
public long getCooldown() {
return this.cooldown;
}
public long getShootCooldown() {
return this.shootCooldown;
}
public long getCrushCooldown() {
return this.crushCooldown;
}
@Override
public boolean isSneakAbility() {
return true;
}
@Override
public boolean isHarmlessAbility() {
return false;
}
public boolean isBeingWorn() {
return this.isBeingWorn;
}
public void setBeingWorn(final boolean isBeingWorn) {
this.isBeingWorn = isBeingWorn;
}
public boolean isControlling() {
return this.isControlling;
}
public void setControlling(final boolean isControlling) {
this.isControlling = isControlling;
}
public boolean isCanThrow() {
return this.canThrow;
}
public void setCanThrow(final boolean canThrow) {
this.canThrow = canThrow;
}
public boolean isMagnetized() {
return this.isMagnetized;
}
public void setMagnetized(final boolean isMagnetized) {
this.isMagnetized = isMagnetized;
}
public boolean isCanUse4Clips() {
return this.canUse4Clips;
}
public void setCanUse4Clips(final boolean canUse4Clips) {
this.canUse4Clips = canUse4Clips;
}
public boolean isCanLoot() {
return this.canLoot;
}
public void setCanLoot(final boolean canLoot) {
this.canLoot = canLoot;
}
public int getMetalClipsCount() {
return this.metalClipsCount;
}
public void setMetalClipsCount(final int metalClipsCount) {
this.metalClipsCount = metalClipsCount;
}
public int getAbilityType() {
return this.abilityType;
}
public void setAbilityType(final int abilityType) {
this.abilityType = abilityType;
}
public int getArmorTime() {
return this.armorTime;
}
public void setArmorTime(final int armorTime) {
this.armorTime = armorTime;
}
public double getCrushDamage() {
return this.crushDamage;
}
public void setCrushDamage(final double crushDamage) {
this.crushDamage = crushDamage;
}
public int getMagnetRange() {
return this.magnetRange;
}
public void setMagnetRange(final int magnetRange) {
this.magnetRange = magnetRange;
}
public long getArmorStartTime() {
return this.armorStartTime;
}
public void setArmorStartTime(final long armorStartTime) {
this.armorStartTime = armorStartTime;
}
public double getMagnetSpeed() {
return this.magnetSpeed;
}
public void setMagnetSpeed(final double magnetSpeed) {
this.magnetSpeed = magnetSpeed;
}
public double getRange() {
return this.range;
}
public void setRange(final double range) {
this.range = range;
}
public LivingEntity getTargetEntity() {
return this.targetEntity;
}
public void setTargetEntity(final LivingEntity targetEntity) {
this.targetEntity = targetEntity;
}
public List<Item> getTrackedIngots() {
return this.trackedIngots;
}
public void setCooldown(final long cooldown) {
this.cooldown = cooldown;
}
}