package com.nisovin.magicspells.spells.targeted;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.Subspell;
import com.nisovin.magicspells.events.SpellTargetEvent;
import com.nisovin.magicspells.materials.MagicMaterial;
import com.nisovin.magicspells.spelleffects.EffectPosition;
import com.nisovin.magicspells.spells.TargetedLocationSpell;
import com.nisovin.magicspells.spells.TargetedSpell;
import com.nisovin.magicspells.util.MagicConfig;
public class CarpetSpell extends TargetedSpell implements TargetedLocationSpell {
int radius;
MagicMaterial block;
int duration;
boolean circle;
int touchCheckInterval;
boolean removeOnTouch;
Subspell spellOnTouch;
Map<Block, Player> blockMap;
TouchChecker checker;
public CarpetSpell(MagicConfig config, String spellName) {
super(config, spellName);
radius = getConfigInt("radius", 1);
block = MagicSpells.getItemNameResolver().resolveBlock(getConfigString("block", "carpet:0"));
duration = getConfigInt("duration", 0);
circle = getConfigBoolean("circle", false);
if (configKeyExists("spell-on-touch")) {
touchCheckInterval = getConfigInt("touch-check-interval", 3);
removeOnTouch = getConfigBoolean("remove-on-touch", true);
spellOnTouch = new Subspell(getConfigString("spell-on-touch", ""));
blockMap = new HashMap<Block, Player>();
checker = new TouchChecker();
}
}
@Override
public void initialize() {
super.initialize();
if (spellOnTouch != null && !spellOnTouch.process()) {
MagicSpells.error("Invalid spell-on-touch for " + internalName);
}
}
@Override
public void turnOff() {
if (blockMap != null) {
blockMap.clear();
}
if (checker != null) {
checker.stop();
}
}
@Override
public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) {
if (state == SpellCastState.NORMAL) {
Location loc = null;
if (targetSelf) {
loc = player.getLocation();
} else {
Block b = getTargetedBlock(player, power);
if (b != null && b.getType() != Material.AIR) {
loc = b.getLocation();
}
}
if (loc == null) {
return noTarget(player);
}
layCarpet(player, loc, power);
}
return PostCastAction.ALREADY_HANDLED;
}
void layCarpet(Player player, Location loc, float power) {
if (!loc.getBlock().getType().isOccluding()) {
int c = 0;
while (!loc.getBlock().getRelative(0, -1, 0).getType().isOccluding() && c <= 2) {
loc.subtract(0, 1, 0);
c++;
}
} else {
int c = 0;
while (loc.getBlock().getType().isOccluding() && c <= 2) {
loc.add(0, 1, 0);
c++;
}
}
int rad = Math.round(radius * power);
Block b;
int y = loc.getBlockY();
final List<Block> blocks = new ArrayList<Block>();
for (int x = loc.getBlockX() - rad; x <= loc.getBlockX() + rad; x++) {
for (int z = loc.getBlockZ() - rad; z <= loc.getBlockZ() + rad; z++) {
b = loc.getWorld().getBlockAt(x, y, z);
if (circle) {
if (loc.getBlock().getLocation().distanceSquared(b.getLocation()) > radius * radius) {
continue;
}
}
if (b.getType().isOccluding()) {
b = b.getRelative(0, 1, 0);
} else if (!b.getRelative(0, -1, 0).getType().isOccluding()) {
b = b.getRelative(0, -1, 0);
}
if (b.getType() == Material.AIR && b.getRelative(0, -1, 0).getType().isSolid()) {
block.setBlock(b, false);
blocks.add(b);
if (blockMap != null) {
blockMap.put(b, player);
}
playSpellEffects(EffectPosition.TARGET, b.getLocation().add(0.5, 0, 0.5));
}
}
}
if (duration > 0 && blocks.size() > 0) {
MagicSpells.scheduleDelayedTask(new Runnable() {
public void run() {
for (Block b : blocks) {
if (block.equals(b)) {
b.setType(Material.AIR);
if (blockMap != null) {
blockMap.remove(b);
}
}
}
}
}, duration);
}
if (player != null) {
playSpellEffects(EffectPosition.CASTER, player);
}
}
@Override
public boolean castAtLocation(Player caster, Location target, float power) {
if (targetSelf) {
layCarpet(caster, caster.getLocation(), power);
} else {
layCarpet(caster, target, power);
}
return true;
}
@Override
public boolean castAtLocation(Location target, float power) {
layCarpet(null, target, power);
return true;
}
class TouchChecker implements Runnable {
int taskId;
public TouchChecker() {
taskId = MagicSpells.scheduleRepeatingTask(this, touchCheckInterval, touchCheckInterval);
}
public void run() {
if (blockMap.size() > 0) {
for (Player player : Bukkit.getOnlinePlayers()) {
Block b = player.getLocation().getBlock();
Player caster = blockMap.get(b);
if (caster != null && block.equals(b) && player != caster) {
SpellTargetEvent event = new SpellTargetEvent(spellOnTouch.getSpell(), caster, player, 1f);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
boolean casted = spellOnTouch.castAtEntity(caster, player, event.getPower());
if (casted && removeOnTouch) {
b.setType(Material.AIR);
blockMap.remove(b);
}
}
}
}
}
}
public void stop() {
MagicSpells.cancelTask(taskId);
}
}
}