package com.nisovin.magicspells.spells.instant;
import java.util.ArrayList;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.util.Vector;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.materials.MagicMaterial;
import com.nisovin.magicspells.spelleffects.EffectPosition;
import com.nisovin.magicspells.spells.InstantSpell;
import com.nisovin.magicspells.util.BlockUtils;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.TemporaryBlockSet;
import com.nisovin.magicspells.util.TemporaryBlockSet.BlockSetRemovalCallback;
public class WallSpell extends InstantSpell {
private int distance;
private int wallWidth;
private int wallHeight;
private int wallDepth;
private int yOffset;
private MagicMaterial wallMaterial;
private int wallDuration;
private boolean alwaysOnGround;
private boolean preventBreaking;
private boolean preventDrops;
private boolean checkPlugins;
private boolean checkPluginsPerBlock;
private String strNoTarget;
private ArrayList<TemporaryBlockSet> blockSets;
public WallSpell(MagicConfig config, String spellName) {
super(config, spellName);
distance = getConfigInt("distance", 3);
wallWidth = getConfigInt("wall-width", 5);
wallHeight = getConfigInt("wall-height", 3);
wallDepth = getConfigInt("wall-depth", 1);
yOffset = getConfigInt("y-offset", -1);
String type = getConfigString("wall-type", "stone");
wallMaterial = MagicSpells.getItemNameResolver().resolveBlock(type);
wallDuration = getConfigInt("wall-duration", 15);
alwaysOnGround = getConfigBoolean("always-on-ground", false);
preventBreaking = getConfigBoolean("prevent-breaking", false);
preventDrops = getConfigBoolean("prevent-drops", true);
checkPlugins = getConfigBoolean("check-plugins", true);
checkPluginsPerBlock = getConfigBoolean("check-plugins-per-block", checkPlugins);
strNoTarget = getConfigString("str-no-target", "Unable to create a wall.");
blockSets = new ArrayList<TemporaryBlockSet>();
}
@Override
public void initialize() {
super.initialize();
if ((preventBreaking || preventDrops) && wallDuration > 0) {
registerEvents(new BreakListener());
}
}
@Override
public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) {
if (state == SpellCastState.NORMAL) {
Block target = getTargetedBlock(player, (distance > 0 && distance < 15) ? distance : 3);
if (target == null || target.getType() != Material.AIR) {
// fail
sendMessage(player, strNoTarget);
return PostCastAction.ALREADY_HANDLED;
} else {
// check plugins
if (checkPlugins) {
BlockState eventBlockState = target.getState();
wallMaterial.setBlock(target, false);
BlockPlaceEvent event = new BlockPlaceEvent(target, eventBlockState, target, player.getItemInHand(), player, true);
Bukkit.getPluginManager().callEvent(event);
BlockUtils.setTypeAndData(target, Material.AIR, (byte)0, false);
if (event.isCancelled()) {
sendMessage(player, strNoTarget);
return PostCastAction.ALREADY_HANDLED;
}
}
if (alwaysOnGround) {
yOffset = 0;
Block b = target.getRelative(0, -1, 0);
while (b.getType() == Material.AIR && yOffset > -5) {
yOffset--;
b = b.getRelative(0, -1, 0);
}
}
TemporaryBlockSet blockSet = new TemporaryBlockSet(Material.AIR, wallMaterial, checkPluginsPerBlock, player);
Location loc = target.getLocation();
Vector dir = player.getLocation().getDirection();
int wallWidth = Math.round(this.wallWidth*power);
int wallHeight = Math.round(this.wallHeight*power);
if (Math.abs(dir.getX()) > Math.abs(dir.getZ())) {
int depthDir = dir.getX() > 0 ? 1 : -1;
for (int z = loc.getBlockZ() - (wallWidth/2); z <= loc.getBlockZ() + (wallWidth/2); z++) {
for (int y = loc.getBlockY() + yOffset; y < loc.getBlockY() + wallHeight + yOffset; y++) {
for (int x = target.getX(); x < target.getX() + wallDepth && x > target.getX() - wallDepth; x += depthDir) {
blockSet.add(player.getWorld().getBlockAt(x, y, z));
}
}
}
} else {
int depthDir = dir.getZ() > 0 ? 1 : -1;
for (int x = loc.getBlockX() - (wallWidth/2); x <= loc.getBlockX() + (wallWidth/2); x++) {
for (int y = loc.getBlockY() + yOffset; y < loc.getBlockY() + wallHeight + yOffset; y++) {
for (int z = target.getZ(); z < target.getZ() + wallDepth && z > target.getZ() - wallDepth; z += depthDir) {
blockSet.add(player.getWorld().getBlockAt(x, y, z));
}
}
}
}
if (wallDuration > 0) {
blockSets.add(blockSet);
blockSet.removeAfter(Math.round(wallDuration*power), new BlockSetRemovalCallback() {
@Override
public void run(TemporaryBlockSet set) {
blockSets.remove(set);
}
});
}
playSpellEffects(EffectPosition.CASTER, player);
}
}
return PostCastAction.HANDLE_NORMALLY;
}
class BreakListener implements Listener {
@EventHandler(ignoreCancelled=true)
void onBlockBreak(BlockBreakEvent event) {
if (blockSets.size() > 0) {
for (TemporaryBlockSet blockSet : blockSets) {
if (blockSet.contains(event.getBlock())) {
event.setCancelled(true);
if (!preventBreaking) {
event.getBlock().setType(Material.AIR);
}
}
}
}
}
}
@Override
public void turnOff() {
for (TemporaryBlockSet blockSet : blockSets) {
blockSet.remove();
}
blockSets.clear();
}
}