TF-ProjectKorra/src/com/projectkorra/projectkorra/waterbending/WaterSpout.java
Moros 10ac727eda
Fix deprecated calls (#1072)
Update some deprecated calls
## Fixes
* Fixes the server loading the legacy `Material` API when a player used `TremorSense`
## Changes
* Added boundaries to `Levelled` block data in `GeneralMethods::getWaterData` and `GeneralMethods::getLavaData` to avoid future bugs
2020-07-21 14:57:07 -07:00

463 lines
13 KiB
Java

package com.projectkorra.projectkorra.waterbending;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
import com.projectkorra.projectkorra.GeneralMethods;
import com.projectkorra.projectkorra.ability.ElementalAbility;
import com.projectkorra.projectkorra.ability.WaterAbility;
import com.projectkorra.projectkorra.ability.util.Collision;
import com.projectkorra.projectkorra.attribute.Attribute;
import com.projectkorra.projectkorra.util.ParticleEffect;
import com.projectkorra.projectkorra.util.TempBlock;
public class WaterSpout extends WaterAbility {
private static final Map<Block, Block> AFFECTED_BLOCKS = new ConcurrentHashMap<Block, Block>();
private final List<TempBlock> blocks = new ArrayList<TempBlock>();
@Attribute("CanBendOnPackedIce")
private boolean canBendOnPackedIce;
private boolean useParticles;
private boolean useBlockSpiral;
private int angle;
private long time;
private long interval;
@Attribute(Attribute.COOLDOWN)
private long cooldown;
@Attribute(Attribute.DURATION)
private long duration;
private long startTime;
private double rotation;
private double height;
@Attribute(Attribute.HEIGHT)
private double maxHeight;
private Block base;
private TempBlock baseBlock;
public WaterSpout(final Player player) {
super(player);
final WaterSpout oldSpout = getAbility(player, WaterSpout.class);
if (oldSpout != null) {
oldSpout.remove();
return;
}
this.canBendOnPackedIce = getConfig().getStringList("Properties.Water.IceBlocks").contains(Material.PACKED_ICE.toString());
this.useParticles = getConfig().getBoolean("Abilities.Water.WaterSpout.Particles");
this.useBlockSpiral = getConfig().getBoolean("Abilities.Water.WaterSpout.BlockSpiral");
this.cooldown = getConfig().getLong("Abilities.Water.WaterSpout.Cooldown");
this.height = getConfig().getDouble("Abilities.Water.WaterSpout.Height");
this.interval = getConfig().getLong("Abilities.Water.WaterSpout.Interval");
this.duration = getConfig().getLong("Abilities.Water.WaterSpout.Duration");
this.startTime = System.currentTimeMillis();
this.maxHeight = this.getNightFactor(this.height);
final WaterSpoutWave spoutWave = new WaterSpoutWave(player, WaterSpoutWave.AbilityType.CLICK);
if (spoutWave.isStarted() && !spoutWave.isRemoved()) {
return;
}
Block topBlock = GeneralMethods.getTopBlock(player.getLocation(), (int) -this.getNightFactor(this.height), (int) -this.getNightFactor(this.height));
if (topBlock == null) {
topBlock = player.getLocation().getBlock();
}
if (!isWater(topBlock) && !this.isIcebendable(topBlock) && !isSnow(topBlock)) {
return;
} else if (topBlock.getType() == Material.PACKED_ICE && !this.canBendOnPackedIce) {
return;
}
final double heightRemoveThreshold = 2;
if (!this.isWithinMaxSpoutHeight(topBlock.getLocation(), heightRemoveThreshold)) {
return;
}
this.flightHandler.createInstance(player, this.getName());
player.setAllowFlight(true);
this.spoutableWaterHeight(player.getLocation()); // Sets base.
this.start();
}
private void displayWaterSpiral(final Location location) {
if (!this.useBlockSpiral) {
return;
}
final double maxHeight = this.player.getLocation().getY() - location.getY() - .5;
double height = 0;
this.rotation += .4;
int i = 0;
while (height < maxHeight) {
i += 20;
height += .4;
final double angle = (i * Math.PI / 180);
final double x = 1 * Math.cos(angle + this.rotation);
final double z = 1 * Math.sin(angle + this.rotation);
final Location loc = location.clone().getBlock().getLocation().add(.5, .5, .5);
loc.add(x, height, z);
final Block block = loc.getBlock();
if ((!TempBlock.isTempBlock(block)) && (ElementalAbility.isAir(block.getType()) || !GeneralMethods.isSolid(block))) {
this.blocks.add(new TempBlock(block, GeneralMethods.getWaterData(7)));
AFFECTED_BLOCKS.put(block, block);
}
}
}
@Override
public void progress() {
for (final TempBlock tb : this.blocks) {
AFFECTED_BLOCKS.remove(tb.getBlock());
tb.revertBlock();
}
if (this.player.isDead() || !this.player.isOnline() || !this.bPlayer.canBendIgnoreBindsCooldowns(this)) {
this.remove();
return;
} else if (this.duration != 0 && System.currentTimeMillis() > this.startTime + this.duration) {
this.bPlayer.addCooldown(this);
this.remove();
return;
} else {
this.blocks.clear();
this.player.setFallDistance(0);
this.player.setSprinting(false);
if ((new Random()).nextInt(10) == 0) {
playWaterbendingSound(this.player.getLocation());
}
this.player.removePotionEffect(PotionEffectType.SPEED);
Location location = this.player.getLocation().clone().add(0, .2, 0);
Block block = location.clone().getBlock();
final double height = this.spoutableWaterHeight(location);
if (height != -1) {
location = this.base.getLocation();
final double heightRemoveThreshold = 2;
if (!this.isWithinMaxSpoutHeight(location, heightRemoveThreshold)) {
this.bPlayer.addCooldown(this);
this.remove();
return;
}
for (int i = 1; i <= height; i++) {
block = location.clone().add(0, i, 0).getBlock();
if (!TempBlock.isTempBlock(block)) {
this.blocks.add(new TempBlock(block, Material.WATER));
AFFECTED_BLOCKS.put(block, block);
}
this.rotateParticles(block);
}
this.displayWaterSpiral(location.clone().add(.5, 0, .5));
if (this.player.getLocation().getBlockY() > block.getY()) {
if (this.player.isFlying()) {
this.player.setFlying(false);
}
} else {
if (!this.player.isFlying()) {
this.player.setAllowFlight(true);
this.player.setFlying(true);
}
}
} else {
this.bPlayer.addCooldown(this);
this.remove();
return;
}
}
}
@Override
public void remove() {
super.remove();
this.revertBaseBlock();
for (final TempBlock tb : this.blocks) {
AFFECTED_BLOCKS.remove(tb.getBlock());
tb.revertBlock();
}
this.flightHandler.removeInstance(this.player, this.getName());
}
public void revertBaseBlock() {
if (this.baseBlock != null) {
this.baseBlock.revertBlock();
this.baseBlock = null;
}
}
private boolean isWithinMaxSpoutHeight(final Location baseBlockLocation, final double threshold) {
if (baseBlockLocation == null) {
return false;
}
final double playerHeight = this.player.getLocation().getY();
if (playerHeight > baseBlockLocation.getY() + this.maxHeight + threshold) {
return false;
}
return true;
}
public void rotateParticles(final Block block) {
if (!this.useParticles) {
return;
}
if (System.currentTimeMillis() >= this.time + this.interval) {
this.time = System.currentTimeMillis();
Location location = block.getLocation();
final Location playerLoc = this.player.getLocation();
location = new Location(location.getWorld(), playerLoc.getX(), location.getY(), playerLoc.getZ());
double dy = playerLoc.getY() - block.getY();
if (dy > this.height) {
dy = this.height;
}
final double[] directions = { -0.5, 0.325, 0.25, 0.125, 0.0, 0.125, 0.25, 0.325, 0.5 };
int index = this.angle;
this.angle++;
if (this.angle >= directions.length) {
this.angle = 0;
}
for (int i = 1; i <= dy; i++) {
index += 1;
if (index >= directions.length) {
index = 0;
}
final Location effectLoc2 = new Location(location.getWorld(), location.getX(), block.getY() + i, location.getZ());
ParticleEffect.WATER_SPLASH.display(effectLoc2, 5, directions[index], directions[index], directions[index]);
}
}
}
private double spoutableWaterHeight(final Location location) {
double newHeight = this.height;
if (isNight(this.player.getWorld())) {
newHeight = this.getNightFactor(newHeight);
}
this.maxHeight = newHeight + 5;
Block blocki;
for (int i = 0; i < this.maxHeight; i++) {
blocki = location.clone().add(0, -i, 0).getBlock();
if (GeneralMethods.isRegionProtectedFromBuild(this, blocki.getLocation())) {
return -1;
}
if (TempBlock.get(blocki) == null || !this.blocks.contains(TempBlock.get(blocki))) {
if (isWater(blocki)) {
if (!TempBlock.isTempBlock(blocki)) {
this.revertBaseBlock();
}
this.base = blocki;
if (i > newHeight) {
return newHeight;
}
return i;
}
if (this.isIcebendable(blocki) || isSnow(blocki)) {
if (this.isIcebendable(blocki)) {
if (blocki.getType() == Material.PACKED_ICE && !this.canBendOnPackedIce) {
this.remove();
return -1;
}
}
if (!TempBlock.isTempBlock(blocki)) {
this.revertBaseBlock();
this.baseBlock = new TempBlock(blocki, Material.WATER);
}
this.base = blocki;
if (i > newHeight) {
return newHeight;
}
return i;
}
if ((!ElementalAbility.isAir(blocki.getType()) && (!isPlant(blocki) || !this.bPlayer.canPlantbend()))) {
this.revertBaseBlock();
return -1;
}
}
}
return -1;
}
/**
* This method was used for the old collision detection system. Please see
* {@link Collision} for the new system.
*/
@Deprecated
public static boolean removeSpouts(final Location loc0, final double radius, final Player sourcePlayer) {
boolean removed = false;
for (final WaterSpout spout : getAbilities(WaterSpout.class)) {
if (!spout.player.equals(sourcePlayer)) {
final Location top = spout.getLocation();
final Location base = spout.getBase().getLocation();
final double dist = top.getBlockY() - base.getBlockY();
for (double d = 0; d <= dist; d += 0.5) {
final Location spoutLoc = base.clone().add(0, d, 0);
if (loc0.getWorld().equals(spoutLoc.getWorld()) && loc0.distance(spoutLoc) <= radius) {
removed = true;
spout.remove();
}
}
}
}
return removed;
}
@Override
public String getName() {
return "WaterSpout";
}
@Override
public Location getLocation() {
return this.player != null ? this.player.getLocation() : null;
}
@Override
public long getCooldown() {
return this.cooldown;
}
@Override
public boolean isSneakAbility() {
return false;
}
@Override
public boolean isHarmlessAbility() {
return true;
}
@Override
public boolean isCollidable() {
return true;
}
@Override
public List<Location> getLocations() {
if (this.getBase() == null) {
return new ArrayList<>();
}
final ArrayList<Location> locations = new ArrayList<>();
final Location top = this.getLocation();
final Location iterLoc = this.getBase().getLocation();
final double ySpacing = 2;
while (iterLoc.getY() <= top.getY()) {
locations.add(iterLoc.clone());
iterLoc.add(0, ySpacing, 0);
}
return locations;
}
public boolean isCanBendOnPackedIce() {
return this.canBendOnPackedIce;
}
public void setCanBendOnPackedIce(final boolean canBendOnPackedIce) {
this.canBendOnPackedIce = canBendOnPackedIce;
}
public boolean isUseParticles() {
return this.useParticles;
}
public void setUseParticles(final boolean useParticles) {
this.useParticles = useParticles;
}
public boolean isUseBlockSpiral() {
return this.useBlockSpiral;
}
public void setUseBlockSpiral(final boolean useBlockSpiral) {
this.useBlockSpiral = useBlockSpiral;
}
public int getAngle() {
return this.angle;
}
public void setAngle(final int angle) {
this.angle = angle;
}
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 getRotation() {
return this.rotation;
}
public void setRotation(final double rotation) {
this.rotation = rotation;
}
public double getHeight() {
return this.height;
}
public void setHeight(final double height) {
this.height = height;
}
public Block getBase() {
return this.base;
}
public void setBase(final Block base) {
this.base = base;
}
public TempBlock getBaseBlock() {
return this.baseBlock;
}
public void setBaseBlock(final TempBlock baseBlock) {
this.baseBlock = baseBlock;
}
public static Map<Block, Block> getAffectedBlocks() {
return AFFECTED_BLOCKS;
}
}