package com.nisovin.magicspells.spells.targeted;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Snowball;
import org.bukkit.util.Vector;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.spelleffects.EffectPosition;
import com.nisovin.magicspells.spells.TargetedEntityFromLocationSpell;
import com.nisovin.magicspells.spells.TargetedEntitySpell;
import com.nisovin.magicspells.spells.TargetedSpell;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.TargetInfo;
public class HomingArrowSpell extends TargetedSpell implements TargetedEntitySpell, TargetedEntityFromLocationSpell {
float velocity;
int specialEffectInterval = 0;
Class<? extends Projectile> projectileType = Snowball.class;
List<HomingArrow> arrows = new ArrayList<HomingArrow>();
int monitor = 0;
public HomingArrowSpell(MagicConfig config, String spellName) {
super(config, spellName);
velocity = getConfigFloat("velocity", 1F);
specialEffectInterval = getConfigInt("special-effect-interval", 0);
}
private void fireHomingArrow(Player player, Location from, LivingEntity target, float power) {
Projectile projectile = null;
Vector v = null;
if (from != null) {
v = target.getLocation().toVector().subtract(from.toVector()).normalize();
from = from.clone().setDirection(v);
projectile = from.getWorld().spawn(from, projectileType);
if (player != null) {
projectile.setShooter(player);
}
} else if (player != null) {
projectile = player.launchProjectile(projectileType);
v = player.getLocation().getDirection();
} else {
return;
}
v.multiply(velocity * power);
projectile.setVelocity(v);
arrows.add(new HomingArrow(player, projectile, target, power));
if (monitor == 0) {
monitor = MagicSpells.scheduleRepeatingTask(new HomingArrowMonitor(), 1, 1);
}
if (from != null) {
playSpellEffects(EffectPosition.CASTER, from);
} else if (player != null) {
playSpellEffects(EffectPosition.CASTER, player);
}
}
@Override
public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) {
if (state == SpellCastState.NORMAL) {
TargetInfo<LivingEntity> targetInfo = getTargetedEntity(player, power);
if (targetInfo == null) {
return noTarget(player);
}
fireHomingArrow(player, null, targetInfo.getTarget(), targetInfo.getPower());
sendMessages(player, targetInfo.getTarget());
return PostCastAction.NO_MESSAGES;
}
return PostCastAction.HANDLE_NORMALLY;
}
@Override
public boolean castAtEntity(Player caster, LivingEntity target, float power) {
if (validTargetList.canTarget(caster, target)) {
fireHomingArrow(caster, null, target, power);
return true;
} else {
return false;
}
}
@Override
public boolean castAtEntity(LivingEntity target, float power) {
return false;
}
@Override
public boolean castAtEntityFromLocation(Player caster, Location from, LivingEntity target, float power) {
if (validTargetList.canTarget(caster, target)) {
fireHomingArrow(caster, from, target, power);
return true;
} else {
return false;
}
}
@Override
public boolean castAtEntityFromLocation(Location from, LivingEntity target, float power) {
if (validTargetList.canTarget(target)) {
fireHomingArrow(null, from, target, power);
return true;
} else {
return false;
}
}
class HomingArrowMonitor implements Runnable {
int c = 0;
public void run() {
c++;
Iterator<HomingArrow> iter = arrows.iterator();
while (iter.hasNext()) {
HomingArrow arrow = iter.next();
if (arrow.arrow.isDead() || arrow.arrow.isOnGround() || arrow.target.isDead() || !arrow.target.isValid()) {
iter.remove();
playSpellEffects(EffectPosition.TARGET, arrow.arrow.getLocation());
} else { // if (arrow.arrow.getLocation().distanceSquared(arrow.target.getLocation()) > 5 * 5) {
Vector v = arrow.target.getLocation().add(0, 0.75, 0).toVector().subtract(arrow.arrow.getLocation().toVector()).normalize();
v.multiply(velocity * arrow.power);
v.setY(v.getY() + 0.15);
arrow.arrow.setVelocity(v);
//Location l = arrow.arrow.getLocation().setDirection(v);
//arrow.arrow.teleport(l);
if (specialEffectInterval > 0 && c % specialEffectInterval == 0) {
playSpellEffects(EffectPosition.SPECIAL, arrow.arrow.getLocation());
}
}
}
if (arrows.size() == 0) {
MagicSpells.cancelTask(monitor);
monitor = 0;
}
}
}
class HomingArrow {
Player shooter;
Projectile arrow;
LivingEntity target;
float power;
public HomingArrow(Player shooter, Projectile arrow, LivingEntity target, float power) {
this.shooter = shooter;
this.arrow = arrow;
this.target = target;
this.power = power;
}
}
}