package com.nisovin.magicspells.spells.targeted;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Player;
import org.bukkit.material.Vine;
import com.nisovin.magicspells.spells.TargetedSpell;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.SpellAnimation;
public class VinesSpell extends TargetedSpell {
int up;
int down;
int width;
int animateInterval;
public VinesSpell(MagicConfig config, String spellName) {
super(config, spellName);
up = getConfigInt("up", 3);
down = getConfigInt("down", 1);
width = getConfigInt("width", 1);
animateInterval = getConfigInt("animate-interval", 0);
}
@Override
public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) {
if (state == SpellCastState.NORMAL) {
List<Block> target = getLastTwoTargetedBlocks(player, power);
if (target == null || target.size() != 2) {
return noTarget(player);
}
if (target.get(0).getType() != Material.AIR || !target.get(1).getType().isSolid()) {
return noTarget(player);
}
boolean success = growVines(player, target.get(0), target.get(1));
if (!success) {
return noTarget(player);
}
}
return PostCastAction.HANDLE_NORMALLY;
}
private boolean growVines(Player caster, final Block air, Block solid) {
BlockFace face = air.getFace(solid);
int x = 0;
int z = 0;
if (face == BlockFace.NORTH || face == BlockFace.SOUTH) {
x = 1;
} else if (face == BlockFace.EAST || face == BlockFace.WEST) {
z = 1;
} else {
return false;
}
TreeSet<VineBlock> blocks = new TreeSet<VineBlock>();
blocks.add(new VineBlock(air, air));
growVinesVert(blocks, air, solid, air);
if (width > 1) {
for (int i = 1; i <= width / 2; i++) {
Block a = air.getRelative(x * i, 0, z * i);
Block s = solid.getRelative(x * i, 0, z * i);
if (a.getType() == Material.AIR && s.getType().isSolid()) {
blocks.add(new VineBlock(a, air));
growVinesVert(blocks, a, s, air);
} else {
break;
}
}
for (int i = 1; i <= width / 2; i++) {
Block a = air.getRelative(x * -i, 0, z * -i);
Block s = solid.getRelative(x * -i, 0, z * -i);
if (a.getType() == Material.AIR && s.getType().isSolid()) {
blocks.add(new VineBlock(a, air));
growVinesVert(blocks, a, s, air);
} else {
break;
}
}
}
if (blocks.size() == 0) {
return false;
}
if (animateInterval <= 0) {
for (VineBlock vine : blocks) {
setBlockToVine(vine.block, face);
}
} else {
new VineAnimation(face, blocks);
}
return true;
}
private void setBlockToVine(Block block, BlockFace face) {
if (block.getType() == Material.AIR) {
BlockState state = block.getState();
state.setType(Material.VINE);
if (state.getData() instanceof Vine) {
Vine data = (Vine)state.getData();
data.putOnFace(face);
state.setData(data);
}
state.update(true, false);
}
}
private void growVinesVert(Set<VineBlock> blocks, Block air, Block solid, Block center) {
Block b;
for (int i = 1; i <= up; i++) {
b = air.getRelative(0, i, 0);
if (b.getType() == Material.AIR && solid.getRelative(0, i, 0).getType().isSolid()) {
blocks.add(new VineBlock(b, center));
} else {
break;
}
}
for (int i = 1; i <= down; i++) {
b = air.getRelative(0, -i, 0);
if (b.getType() == Material.AIR && solid.getRelative(0, -i, 0).getType().isSolid()) {
blocks.add(new VineBlock(b, center));
} else {
break;
}
}
}
class VineBlock implements Comparable<VineBlock> {
Block block;
double distanceSquared;
public VineBlock(Block block, Block center) {
this.block = block;
this.distanceSquared = block.getLocation().distanceSquared(center.getLocation());
}
@Override
public int compareTo(VineBlock o) {
if (o.distanceSquared < this.distanceSquared) {
return 1;
} else if (o.distanceSquared > this.distanceSquared) {
return -1;
} else {
return o.block.getLocation().toString().compareTo(this.block.getLocation().toString());
}
}
}
class VineAnimation extends SpellAnimation {
BlockFace face;
TreeSet<VineBlock> blocks;
public VineAnimation(BlockFace face, TreeSet<VineBlock> blocks) {
super(animateInterval, true);
this.face = face;
this.blocks = blocks;
}
@Override
protected void onTick(int tick) {
VineBlock block = blocks.pollFirst();
if (block != null) {
setBlockToVine(block.block, face);
} else {
this.stop();
}
}
}
}