package com.nisovin.magicspells.spells.targeted;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.Subspell;
import com.nisovin.magicspells.spells.TargetedEntitySpell;
import com.nisovin.magicspells.spells.TargetedLocationSpell;
import com.nisovin.magicspells.spells.TargetedSpell;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.TargetInfo;
public class HoldRightSpell extends TargetedSpell implements TargetedEntitySpell, TargetedLocationSpell {
Subspell spell;
boolean targetEntity;
boolean targetLocation;
int resetTime;
float maxDuration;
float maxDistance;
// TODO: fix leak
Map<String, CastData> casting = new HashMap<String, CastData>();
public HoldRightSpell(MagicConfig config, String spellName) {
super(config, spellName);
spell = new Subspell(getConfigString("spell", ""));
targetEntity = getConfigBoolean("target-entity", true);
targetLocation = getConfigBoolean("target-location", false);
resetTime = getConfigInt("reset-time", 250);
maxDuration = getConfigFloat("max-duration", 0);
maxDistance = getConfigFloat("max-distance", 0);
}
@Override
public void initialize() {
super.initialize();
if (!spell.process()) {
MagicSpells.error("Invalid spell on " + internalName);
}
}
@Override
public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) {
if (state == SpellCastState.NORMAL) {
CastData data = casting.get(player.getName());
if (data != null && data.isValid(player)) {
data.cast(player);
return PostCastAction.ALREADY_HANDLED;
}
data = null;
if (targetEntity) {
TargetInfo<LivingEntity> target = getTargetedEntity(player, power);
if (target != null) {
data = new CastData(target.getTarget(), target.getPower());
} else {
return noTarget(player);
}
} else if (targetLocation) {
Block block = getTargetedBlock(player, power);
if (block != null && block.getType() != Material.AIR) {
data = new CastData(block.getLocation().add(0.5, 0.5, 0.5), power);
} else {
return noTarget(player);
}
} else {
data = new CastData(power);
}
if (data != null) {
data.cast(player);
casting.put(player.getName(), data);
}
}
return PostCastAction.HANDLE_NORMALLY;
}
@Override
public boolean castAtLocation(Player caster, Location target, float power) {
if (!targetLocation) return false;
CastData data = casting.get(caster.getName());
if (data != null && data.isValid(caster)) {
data.cast(caster);
return true;
}
data = new CastData(target, power);
data.cast(caster);
casting.put(caster.getName(), data);
return true;
}
@Override
public boolean castAtLocation(Location target, float power) {
return false;
}
@Override
public boolean castAtEntity(Player caster, LivingEntity target, float power) {
if (!targetEntity) return false;
CastData data = casting.get(caster.getName());
if (data != null && data.isValid(caster)) {
data.cast(caster);
return true;
}
data = new CastData(target, power);
data.cast(caster);
casting.put(caster.getName(), data);
return true;
}
@Override
public boolean castAtEntity(LivingEntity target, float power) {
return false;
}
class CastData {
long start = System.currentTimeMillis();
long lastCast = 0;
LivingEntity targetEntity = null;
Location targetLocation = null;
float power = 1f;
public CastData(LivingEntity target, float power) {
targetEntity = target;
this.power = power;
}
public CastData(Location target, float power) {
targetLocation = target;
this.power = power;
}
public CastData(float power) {
this.power = power;
}
boolean isValid(Player player) {
if (lastCast < System.currentTimeMillis() - resetTime) return false;
if (maxDuration > 0 && System.currentTimeMillis() - start > maxDuration * 1000) return false;
if (maxDistance > 0) {
Location l = targetLocation;
if (targetEntity != null) l = targetEntity.getLocation();
if (l == null) return false;
if (!l.getWorld().equals(player.getWorld())) return false;
if (l.distanceSquared(player.getLocation()) > maxDistance * maxDistance) return false;
}
return true;
}
void cast(Player caster) {
lastCast = System.currentTimeMillis();
if (targetEntity != null) {
spell.castAtEntity(caster, targetEntity, power);
} else if (targetLocation != null) {
spell.castAtLocation(caster, targetLocation, power);
} else {
spell.cast(caster, power);
}
}
}
}