package com.nisovin.magicspells.spells.buff;
import java.util.HashMap;
import java.util.HashSet;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.util.Vector;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.spells.BuffSpell;
import com.nisovin.magicspells.util.MagicConfig;
public class WindwalkSpell extends BuffSpell {
private int launchSpeed;
private float flySpeed;
private int maxY;
private int maxAltitude;
private boolean cancelOnLand;
private HashSet<String> flyers;
private HashMap<String, Integer> tasks;
private HeightMonitor heightMonitor = null;
public WindwalkSpell(MagicConfig config, String spellName) {
super(config, spellName);
launchSpeed = getConfigInt("launch-speed", 1);
flySpeed = getConfigFloat("fly-speed", 0.1F);
maxY = getConfigInt("max-y", 260);
maxAltitude = getConfigInt("max-altitude", 100);
cancelOnLand = getConfigBoolean("cancel-on-land", true);
flyers = new HashSet<String>();
if (useCostInterval > 0) {
tasks = new HashMap<String, Integer>();
}
}
@Override
public void initialize() {
super.initialize();
if (cancelOnLand) {
registerEvents(new SneakListener());
}
}
@Override
public boolean castBuff(final Player player, float power, String[] args) {
// set flying
if (launchSpeed > 0) {
player.teleport(player.getLocation().add(0, .25, 0));
player.setVelocity(new Vector(0,launchSpeed,0));
}
flyers.add(player.getName());
player.setAllowFlight(true);
player.setFlying(true);
player.setFlySpeed(flySpeed);
// set cost interval
if (useCostInterval > 0 || numUses > 0) {
int taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(MagicSpells.plugin, new Runnable() {
public void run() {
addUseAndChargeCost(player);
}
}, useCostInterval, useCostInterval);
tasks.put(player.getName(), taskId);
}
// start height monitor
if (heightMonitor == null && (maxY > 0 || maxAltitude > 0)) {
heightMonitor = new HeightMonitor();
}
return true;
}
public class SneakListener implements Listener {
@EventHandler(priority=EventPriority.MONITOR)
public void onPlayerToggleSneak(PlayerToggleSneakEvent event) {
if (flyers.contains(event.getPlayer().getName())) {
if (event.getPlayer().getLocation().subtract(0,1,0).getBlock().getType() != Material.AIR) {
turnOff(event.getPlayer());
}
}
}
}
public class HeightMonitor implements Runnable {
int taskId;
public HeightMonitor() {
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(MagicSpells.plugin, this, 20, 20);
}
public void run() {
for (String name : flyers) {
Player p = Bukkit.getPlayerExact(name);
if (p != null && p.isValid()) {
if (maxY > 0) {
int ydiff = p.getLocation().getBlockY() - maxY;
if (ydiff > 0) {
p.setVelocity(p.getVelocity().setY(-ydiff * 1.5));
continue;
}
}
if (maxAltitude > 0) {
int ydiff = p.getLocation().getBlockY() - p.getWorld().getHighestBlockYAt(p.getLocation()) - maxAltitude;
if (ydiff > 0) {
p.setVelocity(p.getVelocity().setY(-ydiff * 1.5));
}
}
}
}
}
public void stop() {
Bukkit.getScheduler().cancelTask(taskId);
}
}
@Override
public void turnOffBuff(final Player player) {
if (flyers.remove(player.getName())) {
player.setFlying(false);
if (player.getGameMode() != GameMode.CREATIVE) {
player.setAllowFlight(false);
}
player.setFlySpeed(0.1F);
player.setFallDistance(0);
}
if (tasks != null && tasks.containsKey(player.getName())) {
int taskId = tasks.remove(player.getName());
Bukkit.getScheduler().cancelTask(taskId);
}
if (heightMonitor != null && flyers.size() == 0) {
heightMonitor.stop();
heightMonitor = null;
}
}
@Override
protected void turnOff() {
HashSet<String> flyers = new HashSet<String>(this.flyers);
for (String name : flyers) {
Player player = Bukkit.getPlayerExact(name);
if (player != null) {
turnOff(player);
}
}
this.flyers.clear();
}
@Override
public boolean isActive(Player player) {
return flyers.contains(player.getName());
}
}