package com.nisovin.magicspells.spells.targeted; import org.bukkit.Location; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; import com.nisovin.magicspells.MagicSpells; import com.nisovin.magicspells.spelleffects.EffectPosition; 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 OrbitSpell extends TargetedSpell implements TargetedEntitySpell { float orbitRadius; float secondsPerRevolution; boolean counterClockwise; String particleName; float particleSpeed; int particleCount; float particleHorizontalSpread; float particleVerticalSpread; int tickInterval; float ticksPerSecond; float distancePerTick; int maxDuration; int renderDistance; float yOffset; boolean targetPlayers; boolean targetNonPlayers; public OrbitSpell(MagicConfig config, String spellName) { super(config, spellName); orbitRadius = getConfigFloat("orbit-radius", 1); secondsPerRevolution = getConfigFloat("seconds-per-revolution", 3); counterClockwise = getConfigBoolean("counter-clockwise", false); particleName = getConfigString("particle-name", "reddust"); particleSpeed = getConfigFloat("particle-speed", 0.3F); particleCount = getConfigInt("particle-count", 15); particleHorizontalSpread = getConfigFloat("particle-horizontal-spread", 0.3F); particleVerticalSpread = getConfigFloat("particle-vertical-spread", 0.3F); tickInterval = getConfigInt("tick-interval", 2); ticksPerSecond = 20F / (float)tickInterval; distancePerTick = 6.28F / (ticksPerSecond * secondsPerRevolution); maxDuration = getConfigInt("max-duration", 20) * 1000; yOffset = getConfigFloat("y-offset", 0.6F); renderDistance = getConfigInt("render-distance", 32); targetPlayers = getConfigBoolean("target-players", true); targetNonPlayers = getConfigBoolean("target-non-players", false); } @Override public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) { if (state == SpellCastState.NORMAL) { TargetInfo<LivingEntity> target = getTargetedEntity(player, power); if (target == null) { return noTarget(player); } new ParticleTracker(player, target.getTarget(), target.getPower()); playSpellEffects(player, target.getTarget()); sendMessages(player, target.getTarget()); return PostCastAction.NO_MESSAGES; } return PostCastAction.HANDLE_NORMALLY; } @Override public boolean castAtEntity(Player caster, LivingEntity target, float power) { new ParticleTracker(caster, target, power); playSpellEffects(caster, target); return true; } @Override public boolean castAtEntity(LivingEntity target, float power) { return false; } class ParticleTracker implements Runnable { Player caster; LivingEntity target; float power; long startTime; Vector currentPosition; int taskId; int counter = 0; public ParticleTracker(Player caster, LivingEntity target, float power) { this.caster = caster; this.target = target; this.power = power; this.startTime = System.currentTimeMillis(); this.currentPosition = target.getLocation().getDirection().setY(0); this.taskId = MagicSpells.scheduleRepeatingTask(this, 0, tickInterval); } @Override public void run() { // check for valid and alive caster and target if (!caster.isValid() || !target.isValid()) { stop(); return; } // check if duration is up if (maxDuration > 0 && startTime + maxDuration < System.currentTimeMillis()) { stop(); return; } // move projectile and calculate new vector Location loc = getLocation(); // show particle MagicSpells.getVolatileCodeHandler().playParticleEffect(loc, particleName, particleHorizontalSpread, particleVerticalSpread, particleSpeed, particleCount, renderDistance, 0F); } private Location getLocation() { Vector perp; if (counterClockwise) { perp = new Vector(currentPosition.getZ(), 0, -currentPosition.getX()); } else { perp = new Vector(-currentPosition.getZ(), 0, currentPosition.getX()); } currentPosition.add(perp.multiply(distancePerTick)).normalize(); return target.getLocation().add(0, yOffset, 0).add(currentPosition.clone().multiply(orbitRadius)); } public void stop() { if (target.isValid()) { playSpellEffects(EffectPosition.DELAYED, getLocation()); } MagicSpells.cancelTask(taskId); caster = null; target = null; currentPosition = null; } } }