mirror of
https://github.com/TotalFreedomMC/TF-ProjectKorra.git
synced 2024-05-29 08:21:25 +00:00
8d7f116c49
This PR moves over some outstanding PR's to the proper branch and resolves some extra issues. Thanks @xNuminousx! ## Additions * Adds Surge interactions with Lava * Surge Wave and Surge Wall will both cause Lava to turn into TempBlock Cobblestone / Obsidian * Enabled via the new `Abilities.Water.Surge.Wave.SolidifyLava.Enabled` and `Abilities.Water.Surge.Wall.SolidifyLava.Enabled` config options. They both default to `true` * Duration of the created TempBlocks is set via the new `Abilities.Water.Surge.Wave.SolidifyLava.Duration` and `Abilities.Water.Surge.Wall.SolidifyLava.Duration` config options. They both default to `36000` ## Fixes * Fixes DensityShift turning non-full blocks into Sand causing the player to get stuck in the ground. Now it will still prevent fall damage on non-full earthbendable blocks but will not turn them to Sand. * Fixes EarthDome and potentially other combos from not respecting their `Enabled` config option * Fixes players with usernames the same as ability names getting incorrect cooldowns applied. Resolves #1068 ## Misc. Changes * Changes Water abilities that require sources to deactivate if their source is destroyed after selection occurs but before the ability starts * Changes AirSuction origin selection to remove if the player gets too far away * Changes AirSwipe streams to be independent of one another (i.e. one hitting a wall won't cause them all to stop) * Reduces the default collision radius of AirSwipe and prevents entities from getting hit through corners * Bumps the Spigot API version to 1.16
985 lines
28 KiB
Java
985 lines
28 KiB
Java
package com.projectkorra.projectkorra.waterbending;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Random;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import org.apache.commons.lang3.tuple.Pair;
|
|
|
|
import org.bukkit.Location;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.block.Block;
|
|
import org.bukkit.entity.Entity;
|
|
import org.bukkit.entity.LivingEntity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.util.Vector;
|
|
|
|
import com.projectkorra.projectkorra.BendingPlayer;
|
|
import com.projectkorra.projectkorra.GeneralMethods;
|
|
import com.projectkorra.projectkorra.ability.AirAbility;
|
|
import com.projectkorra.projectkorra.ability.WaterAbility;
|
|
import com.projectkorra.projectkorra.attribute.Attribute;
|
|
import com.projectkorra.projectkorra.avatar.AvatarState;
|
|
import com.projectkorra.projectkorra.command.Commands;
|
|
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.waterbending.plant.PlantRegrowth;
|
|
import com.projectkorra.projectkorra.waterbending.util.WaterReturn;
|
|
|
|
public class Torrent extends WaterAbility {
|
|
|
|
private static final double CLEANUP_RANGE = 50;
|
|
private static final Map<TempBlock, Pair<Player, Integer>> FROZEN_BLOCKS = new ConcurrentHashMap<>();
|
|
|
|
private boolean sourceSelected;
|
|
private boolean settingUp;
|
|
private boolean forming;
|
|
private boolean formed;
|
|
private boolean launch;
|
|
private boolean launching;
|
|
private boolean freeze;
|
|
private boolean revert;
|
|
private int layer;
|
|
private int maxLayer;
|
|
private int maxHits;
|
|
private int hits = 1;
|
|
private long time;
|
|
private long interval;
|
|
@Attribute(Attribute.COOLDOWN)
|
|
private long cooldown;
|
|
private long revertTime;
|
|
private double startAngle;
|
|
private double angle;
|
|
@Attribute(Attribute.RADIUS)
|
|
private double radius;
|
|
@Attribute(Attribute.KNOCKBACK)
|
|
private double knockback;
|
|
@Attribute(Attribute.KNOCKUP)
|
|
private double knockup;
|
|
@Attribute(Attribute.DAMAGE)
|
|
private double damage;
|
|
@Attribute("Successive" + Attribute.DAMAGE)
|
|
private double successiveDamage;
|
|
@Attribute("Deflect" + Attribute.DAMAGE)
|
|
private double deflectDamage;
|
|
@Attribute(Attribute.RANGE)
|
|
private double range;
|
|
@Attribute(Attribute.SELECT_RANGE)
|
|
private double selectRange;
|
|
private Block sourceBlock;
|
|
private TempBlock source;
|
|
private Location location;
|
|
private ArrayList<TempBlock> blocks;
|
|
private ArrayList<TempBlock> launchedBlocks;
|
|
private ArrayList<Entity> hurtEntities;
|
|
|
|
public Torrent(final Player player) {
|
|
super(player);
|
|
|
|
this.layer = 0;
|
|
this.startAngle = 0;
|
|
this.maxLayer = getConfig().getInt("Abilities.Water.Torrent.MaxLayer");
|
|
this.knockback = getConfig().getDouble("Abilities.Water.Torrent.Knockback");
|
|
this.angle = getConfig().getDouble("Abilities.Water.Torrent.Angle");
|
|
this.radius = getConfig().getDouble("Abilities.Water.Torrent.Radius");
|
|
this.knockup = getConfig().getDouble("Abilities.Water.Torrent.Knockup");
|
|
this.interval = getConfig().getLong("Abilities.Water.Torrent.Interval");
|
|
this.damage = getConfig().getDouble("Abilities.Water.Torrent.InitialDamage");
|
|
this.successiveDamage = getConfig().getDouble("Abilities.Water.Torrent.SuccessiveDamage");
|
|
this.maxHits = getConfig().getInt("Abilities.Water.Torrent.MaxHits");
|
|
this.deflectDamage = getConfig().getDouble("Abilities.Water.Torrent.DeflectDamage");
|
|
this.range = getConfig().getDouble("Abilities.Water.Torrent.Range");
|
|
this.selectRange = getConfig().getDouble("Abilities.Water.Torrent.SelectRange");
|
|
this.cooldown = getConfig().getLong("Abilities.Water.Torrent.Cooldown");
|
|
this.revert = getConfig().getBoolean("Abilities.Water.Torrent.Revert");
|
|
this.revertTime = getConfig().getLong("Abilities.Water.Torrent.RevertTime");
|
|
this.blocks = new ArrayList<>();
|
|
this.launchedBlocks = new ArrayList<>();
|
|
this.hurtEntities = new ArrayList<>();
|
|
|
|
final Torrent oldTorrent = getAbility(player, Torrent.class);
|
|
if (oldTorrent != null) {
|
|
if (!oldTorrent.sourceSelected) {
|
|
oldTorrent.use();
|
|
this.bPlayer.addCooldown("Torrent", oldTorrent.cooldown);
|
|
return;
|
|
} else {
|
|
oldTorrent.remove();
|
|
}
|
|
}
|
|
|
|
if (this.bPlayer.isOnCooldown("Torrent")) {
|
|
return;
|
|
}
|
|
|
|
if (this.bPlayer.isAvatarState()) {
|
|
this.knockback = getConfig().getDouble("Abilities.Avatar.AvatarState.Water.Torrent.Push");
|
|
this.damage = getConfig().getDouble("Abilities.Avatar.AvatarState.Water.Torrent.InitialDamage");
|
|
this.successiveDamage = getConfig().getDouble("Abilities.Avatar.AvatarState.Water.Torrent.SuccessiveDamage");
|
|
this.maxHits = getConfig().getInt("Abilities.Avatar.AvatarState.Water.Torrent.MaxHits");
|
|
}
|
|
|
|
this.time = System.currentTimeMillis();
|
|
this.sourceBlock = BlockSource.getWaterSourceBlock(player, this.selectRange, ClickType.LEFT_CLICK, true, true, this.bPlayer.canPlantbend());
|
|
if (this.sourceBlock != null && !GeneralMethods.isRegionProtectedFromBuild(this, this.sourceBlock.getLocation())) {
|
|
this.sourceSelected = true;
|
|
this.start();
|
|
}
|
|
}
|
|
|
|
private void freeze() {
|
|
if (this.layer == 0) {
|
|
return;
|
|
} else if (!this.bPlayer.canBendIgnoreBindsCooldowns(getAbility("PhaseChange"))) {
|
|
return;
|
|
}
|
|
final List<Block> ice = GeneralMethods.getBlocksAroundPoint(this.location, this.layer);
|
|
final List<Entity> trapped = GeneralMethods.getEntitiesAroundPoint(this.location, this.layer);
|
|
ICE_SETTING: for (final Block block : ice) {
|
|
if (isTransparent(this.player, block) && block.getType() != Material.ICE) {
|
|
for (final Entity entity : trapped) {
|
|
if (entity instanceof Player) {
|
|
if (Commands.invincible.contains(((Player) entity).getName())) {
|
|
return;
|
|
}
|
|
if (!getConfig().getBoolean("Properties.Water.FreezePlayerHead") && GeneralMethods.playerHeadIsInBlock((Player) entity, block)) {
|
|
continue ICE_SETTING;
|
|
}
|
|
if (!getConfig().getBoolean("Properties.Water.FreezePlayerFeet") && GeneralMethods.playerFeetIsInBlock((Player) entity, block)) {
|
|
continue ICE_SETTING;
|
|
}
|
|
}
|
|
}
|
|
final TempBlock tblock = new TempBlock(block, Material.ICE);
|
|
FROZEN_BLOCKS.put(tblock, Pair.of(this.player, this.getId()));
|
|
if (this.revert) {
|
|
tblock.setRevertTime(this.revertTime + (new Random().nextInt((500 + 500) + 1) - 500));
|
|
}
|
|
playIcebendingSound(block.getLocation());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void progress() {
|
|
if (!this.bPlayer.canBendIgnoreCooldowns(this)) {
|
|
this.remove();
|
|
return;
|
|
} else if (!isWaterbendable(this.sourceBlock) && !this.settingUp && !this.forming && !this.formed && !this.launching) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
if (System.currentTimeMillis() > this.time + this.interval) {
|
|
this.time = System.currentTimeMillis();
|
|
|
|
if (this.sourceSelected) {
|
|
if (this.sourceBlock.getLocation().getWorld() != this.player.getWorld()) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
if (this.sourceBlock.getLocation().distanceSquared(this.player.getLocation()) > this.selectRange * this.selectRange) {
|
|
return;
|
|
}
|
|
|
|
if (this.player.isSneaking()) {
|
|
this.sourceSelected = false;
|
|
this.settingUp = true;
|
|
|
|
if (TempBlock.isTempBlock(this.sourceBlock)) {
|
|
final TempBlock origin = TempBlock.get(this.sourceBlock);
|
|
|
|
if (FROZEN_BLOCKS.containsKey(origin)) {
|
|
massThaw(origin);
|
|
} else if (isBendableWaterTempBlock(origin)) {
|
|
origin.revertBlock();
|
|
}
|
|
}
|
|
|
|
if (isPlant(this.sourceBlock) || isSnow(this.sourceBlock)) {
|
|
new PlantRegrowth(this.player, this.sourceBlock);
|
|
this.sourceBlock.setType(Material.AIR);
|
|
} else if (!GeneralMethods.isAdjacentToThreeOrMoreSources(this.sourceBlock)) {
|
|
this.sourceBlock.setType(Material.AIR);
|
|
}
|
|
|
|
this.source = new TempBlock(this.sourceBlock, Material.WATER);
|
|
this.location = this.sourceBlock.getLocation();
|
|
} else {
|
|
playFocusWaterEffect(this.sourceBlock);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (this.settingUp) {
|
|
if (!this.player.isSneaking()) {
|
|
this.location = this.source.getLocation();
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
final Location eyeLoc = this.player.getEyeLocation();
|
|
final double startAngle = this.player.getEyeLocation().getDirection().angle(new Vector(1, 0, 0));
|
|
final double dx = this.radius * Math.cos(startAngle);
|
|
final double dy = 0;
|
|
final double dz = this.radius * Math.sin(startAngle);
|
|
final Location setup = eyeLoc.clone().add(dx, dy, dz);
|
|
|
|
if (!this.location.getWorld().equals(this.player.getWorld())) {
|
|
this.remove();
|
|
return;
|
|
} else if (this.location.distanceSquared(setup) > this.range * this.range) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
if (this.location.getBlockY() > setup.getBlockY()) {
|
|
final Vector direction = new Vector(0, -1, 0);
|
|
this.location = this.location.clone().add(direction);
|
|
} else if (this.location.getBlockY() < setup.getBlockY()) {
|
|
final Vector direction = new Vector(0, 1, 0);
|
|
this.location = this.location.clone().add(direction);
|
|
} else {
|
|
final Vector direction = GeneralMethods.getDirection(this.location, setup).normalize();
|
|
this.location = this.location.clone().add(direction);
|
|
}
|
|
|
|
if (this.location.distanceSquared(setup) <= 1) {
|
|
this.settingUp = false;
|
|
this.source.revertBlock();
|
|
this.source = null;
|
|
this.forming = true;
|
|
} else if (!this.location.getBlock().equals(this.source.getLocation().getBlock())) {
|
|
this.source.revertBlock();
|
|
this.source = null;
|
|
final Block block = this.location.getBlock();
|
|
if (!isTransparent(this.player, block)) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
this.source = new TempBlock(this.location.getBlock(), Material.WATER);
|
|
}
|
|
}
|
|
if (this.forming && !this.player.isSneaking()) {
|
|
this.location = this.player.getEyeLocation().add(this.radius, 0, 0);
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
if (this.forming || this.formed) {
|
|
if ((new Random()).nextInt(4) == 0) {
|
|
playWaterbendingSound(this.location);
|
|
}
|
|
for (double theta = this.startAngle; theta < this.angle + this.startAngle; theta += 20) {
|
|
final Location loc = this.player.getEyeLocation();
|
|
final double phi = Math.toRadians(theta);
|
|
final double dx = Math.cos(phi) * this.radius;
|
|
final double dy = 0;
|
|
final double dz = Math.sin(phi) * this.radius;
|
|
loc.add(dx, dy, dz);
|
|
if (isWater(loc.getBlock()) && GeneralMethods.isAdjacentToThreeOrMoreSources(loc.getBlock())) {
|
|
ParticleEffect.WATER_BUBBLE.display(loc.getBlock().getLocation().clone().add(.5, .5, .5), 5, Math.random(), Math.random(), Math.random(), 0);
|
|
}
|
|
loc.subtract(dx, dy, dz);
|
|
}
|
|
if (this.angle < 220) {
|
|
this.angle += 20;
|
|
} else {
|
|
this.forming = false;
|
|
this.formed = true;
|
|
}
|
|
|
|
this.formRing();
|
|
if (this.blocks.isEmpty()) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
if (this.formed && !this.player.isSneaking() && !this.launch) {
|
|
new TorrentWave(this.player, this.radius);
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
if (this.launch && this.formed) {
|
|
this.launching = true;
|
|
this.launch = false;
|
|
this.formed = false;
|
|
if (!this.launch()) {
|
|
this.returnWater(this.location);
|
|
this.remove();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (this.launching) {
|
|
if (!this.player.isSneaking()) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
if (!this.launch()) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean launch() {
|
|
if (this.launchedBlocks.isEmpty() && this.blocks.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
if (this.launchedBlocks.isEmpty()) {
|
|
this.clearRing();
|
|
final Location loc = this.player.getEyeLocation();
|
|
final ArrayList<Block> doneBlocks = new ArrayList<Block>();
|
|
for (double theta = this.startAngle; theta < this.angle + this.startAngle; theta += 20) {
|
|
final double phi = Math.toRadians(theta);
|
|
final double dx = Math.cos(phi) * this.radius;
|
|
final double dy = 0;
|
|
final double dz = Math.sin(phi) * this.radius;
|
|
final Location blockloc = loc.clone().add(dx, dy, dz);
|
|
|
|
if (Math.abs(theta - this.startAngle) < 10) {
|
|
this.location = blockloc.clone();
|
|
}
|
|
|
|
final Block block = blockloc.getBlock();
|
|
if (!doneBlocks.contains(block) && !GeneralMethods.isRegionProtectedFromBuild(this, blockloc)) {
|
|
if (isTransparent(this.player, block)) {
|
|
this.launchedBlocks.add(new TempBlock(block, Material.WATER));
|
|
doneBlocks.add(block);
|
|
} else if (!isTransparent(this.player, block)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (this.launchedBlocks.isEmpty()) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
final Entity target = GeneralMethods.getTargetedEntity(this.player, this.range, this.hurtEntities);
|
|
Location targetLoc = this.player.getTargetBlock(getTransparentMaterialSet(), (int) this.range).getLocation();
|
|
if (target != null) {
|
|
targetLoc = target.getLocation();
|
|
}
|
|
|
|
final ArrayList<TempBlock> newBlocks = new ArrayList<TempBlock>();
|
|
final List<Entity> entities = GeneralMethods.getEntitiesAroundPoint(this.player.getLocation(), this.range + 5);
|
|
final List<Entity> affectedEntities = new ArrayList<Entity>();
|
|
final Block realBlock = this.launchedBlocks.get(0).getBlock();
|
|
final Vector dir = GeneralMethods.getDirection(this.location, targetLoc).normalize();
|
|
|
|
if (target != null) {
|
|
targetLoc = this.location.clone().add(dir.clone().multiply(10));
|
|
}
|
|
if (this.layer == 0) {
|
|
this.location = this.location.clone().add(dir);
|
|
}
|
|
|
|
final Block locBlock = this.location.getBlock();
|
|
if (this.location.distanceSquared(this.player.getLocation()) > this.range * this.range || GeneralMethods.isRegionProtectedFromBuild(this, this.location)) {
|
|
if (this.layer < this.maxLayer) {
|
|
if (this.freeze || this.layer < 1) {
|
|
this.layer++;
|
|
}
|
|
}
|
|
if (this.launchedBlocks.size() == 1) {
|
|
this.remove();
|
|
return false;
|
|
}
|
|
} else if (!isTransparent(this.player, locBlock)) {
|
|
if (this.layer < this.maxLayer) {
|
|
if (this.layer == 0) {
|
|
this.hurtEntities.clear();
|
|
}
|
|
if (this.freeze || this.layer < 1) {
|
|
this.layer++;
|
|
}
|
|
}
|
|
if (this.freeze) {
|
|
this.freeze();
|
|
} else if (this.launchedBlocks.size() == 1) {
|
|
this.location = realBlock.getLocation();
|
|
this.remove();
|
|
return false;
|
|
}
|
|
} else {
|
|
if (locBlock.equals(realBlock) && this.layer == 0) {
|
|
return true;
|
|
}
|
|
if (locBlock.getLocation().distanceSquared(targetLoc) > 1) {
|
|
if (isWater(locBlock)) {
|
|
ParticleEffect.WATER_BUBBLE.display(locBlock.getLocation().clone().add(.5, .5, .5), 5, Math.random(), Math.random(), Math.random(), 0);
|
|
}
|
|
newBlocks.add(new TempBlock(locBlock, Material.WATER));
|
|
} else {
|
|
if (this.layer < this.maxLayer) {
|
|
if (this.layer == 0) {
|
|
this.hurtEntities.clear();
|
|
}
|
|
if (this.freeze || this.layer < 1) {
|
|
this.layer++;
|
|
}
|
|
}
|
|
if (this.freeze) {
|
|
this.freeze();
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < this.launchedBlocks.size(); i++) {
|
|
final TempBlock block = this.launchedBlocks.get(i);
|
|
if (i == this.launchedBlocks.size() - 1) {
|
|
block.revertBlock();
|
|
} else {
|
|
newBlocks.add(block);
|
|
for (final Entity entity : entities) {
|
|
if (entity.getWorld() != block.getBlock().getWorld()) {
|
|
continue;
|
|
}
|
|
if (entity.getLocation().distanceSquared(block.getLocation()) <= 1.5 * 1.5 && !affectedEntities.contains(entity)) {
|
|
if (i == 0) {
|
|
this.affect(entity, dir);
|
|
} else {
|
|
this.affect(entity, GeneralMethods.getDirection(block.getLocation(), this.launchedBlocks.get(i - 1).getLocation()).normalize());
|
|
}
|
|
affectedEntities.add(entity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.launchedBlocks.clear();
|
|
this.launchedBlocks.addAll(newBlocks);
|
|
|
|
if (this.launchedBlocks.isEmpty()) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void formRing() {
|
|
this.clearRing();
|
|
this.startAngle += 30;
|
|
|
|
final Location loc = this.player.getEyeLocation();
|
|
final ArrayList<Block> doneBlocks = new ArrayList<Block>();
|
|
final ArrayList<Entity> affectedEntities = new ArrayList<Entity>();
|
|
final List<Entity> entities = GeneralMethods.getEntitiesAroundPoint(loc, this.radius + 2);
|
|
|
|
for (double theta = this.startAngle; theta < this.angle + this.startAngle; theta += 20) {
|
|
final double phi = Math.toRadians(theta);
|
|
final double dx = Math.cos(phi) * this.radius;
|
|
final double dy = 0;
|
|
final double dz = Math.sin(phi) * this.radius;
|
|
final Location blockLoc = loc.clone().add(dx, dy, dz);
|
|
final Block block = blockLoc.getBlock();
|
|
if (!doneBlocks.contains(block)) {
|
|
if (isTransparent(this.player, block)) {
|
|
this.blocks.add(new TempBlock(block, Material.WATER));
|
|
doneBlocks.add(block);
|
|
for (final Entity entity : entities) {
|
|
if (entity.getWorld() != blockLoc.getWorld()) {
|
|
continue;
|
|
}
|
|
if (!affectedEntities.contains(entity) && entity.getLocation().distanceSquared(blockLoc) <= 1.5 * 1.5) {
|
|
this.deflect(entity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void clearRing() {
|
|
for (final TempBlock block : this.blocks) {
|
|
block.revertBlock();
|
|
}
|
|
this.blocks.clear();
|
|
}
|
|
|
|
@Override
|
|
public void remove() {
|
|
super.remove();
|
|
this.clearRing();
|
|
for (final TempBlock block : this.launchedBlocks) {
|
|
block.revertBlock();
|
|
}
|
|
|
|
this.launchedBlocks.clear();
|
|
if (this.source != null) {
|
|
this.source.revertBlock();
|
|
}
|
|
|
|
if (this.location != null) {
|
|
this.returnWater(this.location);
|
|
}
|
|
}
|
|
|
|
private void returnWater(final Location location) {
|
|
new WaterReturn(this.player, location.getBlock());
|
|
}
|
|
|
|
public static void create(final Player player) {
|
|
if (hasAbility(player, Torrent.class)) {
|
|
return;
|
|
}
|
|
|
|
if (WaterReturn.hasWaterBottle(player)) {
|
|
final Location eyeLoc = player.getEyeLocation();
|
|
final Block block = eyeLoc.add(eyeLoc.getDirection().normalize()).getBlock();
|
|
if (isTransparent(player, block) && isTransparent(player, eyeLoc.getBlock())) {
|
|
if (block.getType() != Material.WATER) {
|
|
block.setType(Material.WATER);
|
|
block.setBlockData(GeneralMethods.getWaterData(0));
|
|
}
|
|
final Torrent tor = new Torrent(player);
|
|
|
|
if (tor.sourceSelected || tor.settingUp) {
|
|
WaterReturn.emptyWaterBottle(player);
|
|
}
|
|
block.setType(Material.AIR);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void use() {
|
|
this.launch = true;
|
|
if (this.launching) {
|
|
this.freeze = true;
|
|
}
|
|
}
|
|
|
|
private void deflect(final Entity entity) {
|
|
if (entity.getEntityId() == this.player.getEntityId()) {
|
|
return;
|
|
}
|
|
if (GeneralMethods.isRegionProtectedFromBuild(this, entity.getLocation()) || ((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))) {
|
|
return;
|
|
}
|
|
double x, z, vx, vz, mag;
|
|
double angle = 50;
|
|
angle = Math.toRadians(angle);
|
|
|
|
x = entity.getLocation().getX() - this.player.getLocation().getX();
|
|
z = entity.getLocation().getZ() - this.player.getLocation().getZ();
|
|
|
|
mag = Math.sqrt(x * x + z * z);
|
|
|
|
vx = (x * Math.cos(angle) - z * Math.sin(angle)) / mag;
|
|
vz = (x * Math.sin(angle) + z * Math.cos(angle)) / mag;
|
|
|
|
final Vector vec = new Vector(vx, 0, vz).normalize().multiply(this.knockback);
|
|
final Vector velocity = entity.getVelocity();
|
|
|
|
if (this.bPlayer.isAvatarState()) {
|
|
velocity.setX(AvatarState.getValue(vec.getX()));
|
|
velocity.setZ(AvatarState.getValue(vec.getZ()));
|
|
} else {
|
|
velocity.setX(vec.getX());
|
|
velocity.setZ(vec.getY());
|
|
}
|
|
|
|
GeneralMethods.setVelocity(entity, velocity);
|
|
entity.setFallDistance(0);
|
|
if (entity instanceof LivingEntity) {
|
|
final double damageDealt = this.getNightFactor(this.deflectDamage);
|
|
DamageHandler.damageEntity(entity, damageDealt, this);
|
|
AirAbility.breakBreathbendingHold(entity);
|
|
}
|
|
}
|
|
|
|
private void affect(final Entity entity, final Vector direction) {
|
|
if (entity.getEntityId() == this.player.getEntityId()) {
|
|
return;
|
|
}
|
|
if (GeneralMethods.isRegionProtectedFromBuild(this, entity.getLocation()) || (entity instanceof Player && Commands.invincible.contains(((Player) entity).getName()))) {
|
|
return;
|
|
}
|
|
if (direction.getY() > this.knockup) {
|
|
direction.setY(this.knockup);
|
|
}
|
|
if (!this.freeze) {
|
|
entity.setVelocity(direction.multiply(this.knockback));
|
|
}
|
|
if (entity instanceof LivingEntity && !this.hurtEntities.contains(entity)) {
|
|
double damageDealt = this.getNightFactor(this.damage);
|
|
if (this.hits > 1 && this.hits <= this.maxHits) {
|
|
damageDealt = this.getNightFactor(this.successiveDamage);
|
|
}
|
|
if (this.hits == this.maxHits) {
|
|
this.hits = this.maxHits + 1;
|
|
} else {
|
|
this.hits += 1;
|
|
}
|
|
DamageHandler.damageEntity(entity, damageDealt, this);
|
|
AirAbility.breakBreathbendingHold(entity);
|
|
this.hurtEntities.add(entity);
|
|
((LivingEntity) entity).setNoDamageTicks(0);
|
|
}
|
|
}
|
|
|
|
public static void progressAllCleanup() {
|
|
for (final TempBlock block : FROZEN_BLOCKS.keySet()) {
|
|
final Player player = FROZEN_BLOCKS.get(block).getLeft();
|
|
final BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player);
|
|
if (bPlayer == null) {
|
|
FROZEN_BLOCKS.remove(block);
|
|
continue;
|
|
} else if (block.getBlock().getType() != Material.ICE) {
|
|
FROZEN_BLOCKS.remove(block);
|
|
continue;
|
|
} else if (!player.isOnline()) {
|
|
thaw(block);
|
|
continue;
|
|
} else if (block.getBlock().getWorld() != player.getWorld()) {
|
|
thaw(block);
|
|
continue;
|
|
} else if (block.getLocation().distanceSquared(player.getLocation()) > CLEANUP_RANGE * CLEANUP_RANGE || !bPlayer.canBendIgnoreBindsCooldowns(getAbility("Torrent"))) {
|
|
thaw(block);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void thaw(final Block block) {
|
|
if (TempBlock.isTempBlock(block)) {
|
|
final TempBlock tblock = TempBlock.get(block);
|
|
if (FROZEN_BLOCKS.containsKey(tblock)) {
|
|
thaw(tblock);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void thaw(final TempBlock block) {
|
|
block.revertBlock();
|
|
FROZEN_BLOCKS.remove(block);
|
|
}
|
|
|
|
/**
|
|
* Thaws the entire mass of ice created by a torrent that the given block is
|
|
* part of
|
|
*
|
|
* @param origin part of the ice mass created by a torrent
|
|
*/
|
|
public static void massThaw(final TempBlock origin) {
|
|
if (FROZEN_BLOCKS.containsKey(origin)) {
|
|
final Player creator = FROZEN_BLOCKS.get(origin).getLeft();
|
|
final int id = FROZEN_BLOCKS.get(origin).getRight();
|
|
|
|
for (final TempBlock tb : FROZEN_BLOCKS.keySet()) {
|
|
if (tb.equals(origin)) {
|
|
continue;
|
|
}
|
|
|
|
final Player check = FROZEN_BLOCKS.get(tb).getLeft();
|
|
final int id2 = FROZEN_BLOCKS.get(tb).getRight();
|
|
if (creator.equals(check) && id == id2) {
|
|
thaw(tb);
|
|
}
|
|
}
|
|
|
|
thaw(origin);
|
|
}
|
|
}
|
|
|
|
public static boolean canThaw(final Block block) {
|
|
if (TempBlock.isTempBlock(block)) {
|
|
final TempBlock tblock = TempBlock.get(block);
|
|
return !FROZEN_BLOCKS.containsKey(tblock);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static void removeCleanup() {
|
|
for (final TempBlock block : FROZEN_BLOCKS.keySet()) {
|
|
thaw(block);
|
|
}
|
|
}
|
|
|
|
public static boolean wasBrokenFor(final Player player, final Block block) {
|
|
final Torrent torrent = getAbility(player, Torrent.class);
|
|
if (torrent != null) {
|
|
if (torrent.sourceBlock == null) {
|
|
return false;
|
|
}
|
|
if (torrent.sourceBlock.equals(block)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return "Torrent";
|
|
}
|
|
|
|
@Override
|
|
public Location getLocation() {
|
|
return this.location;
|
|
}
|
|
|
|
@Override
|
|
public long getCooldown() {
|
|
return this.cooldown;
|
|
}
|
|
|
|
@Override
|
|
public boolean isSneakAbility() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isHarmlessAbility() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isCollidable() {
|
|
return this.forming || this.formed || this.launch || this.launching;
|
|
}
|
|
|
|
@Override
|
|
public boolean allowBreakPlants() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public List<Location> getLocations() {
|
|
final ArrayList<Location> locations = new ArrayList<>();
|
|
for (final TempBlock tblock : this.blocks) {
|
|
locations.add(tblock.getLocation());
|
|
}
|
|
for (final TempBlock tblock : this.launchedBlocks) {
|
|
locations.add(tblock.getLocation());
|
|
}
|
|
return locations;
|
|
}
|
|
|
|
public boolean isSourceSelected() {
|
|
return this.sourceSelected;
|
|
}
|
|
|
|
public void setSourceSelected(final boolean sourceSelected) {
|
|
this.sourceSelected = sourceSelected;
|
|
}
|
|
|
|
public boolean isSettingUp() {
|
|
return this.settingUp;
|
|
}
|
|
|
|
public void setSettingUp(final boolean settingUp) {
|
|
this.settingUp = settingUp;
|
|
}
|
|
|
|
public boolean isForming() {
|
|
return this.forming;
|
|
}
|
|
|
|
public void setForming(final boolean forming) {
|
|
this.forming = forming;
|
|
}
|
|
|
|
public boolean isFormed() {
|
|
return this.formed;
|
|
}
|
|
|
|
public void setFormed(final boolean formed) {
|
|
this.formed = formed;
|
|
}
|
|
|
|
public boolean isLaunch() {
|
|
return this.launch;
|
|
}
|
|
|
|
public void setLaunch(final boolean launch) {
|
|
this.launch = launch;
|
|
}
|
|
|
|
public boolean isLaunching() {
|
|
return this.launching;
|
|
}
|
|
|
|
public void setLaunching(final boolean launching) {
|
|
this.launching = launching;
|
|
}
|
|
|
|
public boolean isFreeze() {
|
|
return this.freeze;
|
|
}
|
|
|
|
public void setFreeze(final boolean freeze) {
|
|
this.freeze = freeze;
|
|
}
|
|
|
|
public int getLayer() {
|
|
return this.layer;
|
|
}
|
|
|
|
public void setLayer(final int layer) {
|
|
this.layer = layer;
|
|
}
|
|
|
|
public int getMaxLayer() {
|
|
return this.maxLayer;
|
|
}
|
|
|
|
public void setMaxLayer(final int maxLayer) {
|
|
this.maxLayer = maxLayer;
|
|
}
|
|
|
|
public long getTime() {
|
|
return this.time;
|
|
}
|
|
|
|
public void setTime(final long time) {
|
|
this.time = time;
|
|
}
|
|
|
|
public long getInterval() {
|
|
return this.interval;
|
|
}
|
|
|
|
public void setInterval(final long interval) {
|
|
this.interval = interval;
|
|
}
|
|
|
|
public double getStartAngle() {
|
|
return this.startAngle;
|
|
}
|
|
|
|
public void setStartAngle(final double startAngle) {
|
|
this.startAngle = startAngle;
|
|
}
|
|
|
|
public double getAngle() {
|
|
return this.angle;
|
|
}
|
|
|
|
public void setAngle(final double angle) {
|
|
this.angle = angle;
|
|
}
|
|
|
|
public double getRadius() {
|
|
return this.radius;
|
|
}
|
|
|
|
public void setRadius(final double radius) {
|
|
this.radius = radius;
|
|
}
|
|
|
|
public double getPush() {
|
|
return this.knockback;
|
|
}
|
|
|
|
public void setPush(final double push) {
|
|
this.knockback = push;
|
|
}
|
|
|
|
public double getMaxUpwardForce() {
|
|
return this.knockup;
|
|
}
|
|
|
|
public void setMaxUpwardForce(final double maxUpwardForce) {
|
|
this.knockup = maxUpwardForce;
|
|
}
|
|
|
|
public double getDamage() {
|
|
return this.damage;
|
|
}
|
|
|
|
public void setDamage(final double damage) {
|
|
this.damage = damage;
|
|
}
|
|
|
|
public double getDeflectDamage() {
|
|
return this.deflectDamage;
|
|
}
|
|
|
|
public void setDeflectDamage(final double deflectDamage) {
|
|
this.deflectDamage = deflectDamage;
|
|
}
|
|
|
|
public double getRange() {
|
|
return this.range;
|
|
}
|
|
|
|
public void setRange(final double range) {
|
|
this.range = range;
|
|
}
|
|
|
|
public double getSelectRange() {
|
|
return this.selectRange;
|
|
}
|
|
|
|
public void setSelectRange(final double selectRange) {
|
|
this.selectRange = selectRange;
|
|
}
|
|
|
|
public Block getSourceBlock() {
|
|
return this.sourceBlock;
|
|
}
|
|
|
|
public void setSourceBlock(final Block sourceBlock) {
|
|
this.sourceBlock = sourceBlock;
|
|
}
|
|
|
|
public TempBlock getSource() {
|
|
return this.source;
|
|
}
|
|
|
|
public void setSource(final TempBlock source) {
|
|
this.source = source;
|
|
}
|
|
|
|
public ArrayList<TempBlock> getBlocks() {
|
|
return this.blocks;
|
|
}
|
|
|
|
public void setBlocks(final ArrayList<TempBlock> blocks) {
|
|
this.blocks = blocks;
|
|
}
|
|
|
|
public static double getCleanupRange() {
|
|
return CLEANUP_RANGE;
|
|
}
|
|
|
|
public static Map<TempBlock, Player> getFrozenBlocks() {
|
|
final Map<TempBlock, Player> blocks = new HashMap<>();
|
|
for (final TempBlock tb : FROZEN_BLOCKS.keySet()) {
|
|
blocks.put(tb, FROZEN_BLOCKS.get(tb).getLeft());
|
|
}
|
|
return blocks;
|
|
}
|
|
|
|
public ArrayList<TempBlock> getLaunchedBlocks() {
|
|
return this.launchedBlocks;
|
|
}
|
|
|
|
public ArrayList<Entity> getHurtEntities() {
|
|
return this.hurtEntities;
|
|
}
|
|
|
|
public void setCooldown(final long cooldown) {
|
|
this.cooldown = cooldown;
|
|
}
|
|
|
|
public void setLocation(final Location location) {
|
|
this.location = location;
|
|
}
|
|
}
|