package com.nisovin.magicspells.spells.targeted; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import com.nisovin.magicspells.MagicSpells; import com.nisovin.magicspells.spelleffects.EffectPosition; import com.nisovin.magicspells.spelleffects.SpellEffect; 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 StunSpell extends TargetedSpell implements TargetedEntitySpell { int duration; Map<String, Long> stunnedPlayersUntil; Map<String, Location> stunnedPlayersLocation; Map<LivingEntity, Long> stunnedEntitiesUntil; Map<LivingEntity, Location> stunnedEntitiesLocation; Listener listener = null; int taskId = -1; public StunSpell(MagicConfig config, String spellName) { super(config, spellName); duration = (int)(getConfigFloat("duration", 10) * 1000); stunnedPlayersUntil = new HashMap<String, Long>(); stunnedPlayersLocation = new HashMap<String, Location>(); stunnedEntitiesUntil = new HashMap<LivingEntity, Long>(); stunnedEntitiesLocation = new HashMap<LivingEntity, Location>(); } @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); } else { LivingEntity target = targetInfo.getTarget(); power = targetInfo.getPower(); if (target instanceof Player) { stunPlayer(player, (Player)target, Math.round(duration * power)); } else { stunEntity(player, target, Math.round(duration * power)); } sendMessages(player, target); return PostCastAction.NO_MESSAGES; } } return PostCastAction.HANDLE_NORMALLY; } void stunPlayer(Player caster, Player target, int duration) { stunnedPlayersUntil.put(target.getName(), System.currentTimeMillis() + duration); stunnedPlayersLocation.put(target.getName(), target.getLocation()); if (listener == null) { listener = new StunListener(); registerEvents(listener); } if (caster != null) { playSpellEffects(caster, target); } else { playSpellEffects(EffectPosition.TARGET, target); } playSpellEffectsBuff(target, new SpellEffect.SpellEffectActiveChecker() { @Override public boolean isActive(Entity entity) { return stunnedPlayersUntil.containsKey(((Player)entity).getName()); } }); } void stunEntity(Player caster, LivingEntity target, int duration) { stunnedEntitiesUntil.put(target, System.currentTimeMillis() + duration); stunnedEntitiesLocation.put(target, target.getLocation()); if (taskId < 0) { taskId = MagicSpells.scheduleRepeatingTask(new StunMonitor(), 5, 5); } if (caster != null) { playSpellEffects(caster, target); } else { playSpellEffects(EffectPosition.TARGET, target); } playSpellEffectsBuff(target, new SpellEffect.SpellEffectActiveChecker() { @Override public boolean isActive(Entity entity) { return stunnedEntitiesUntil.containsKey(entity); } }); } @Override public boolean castAtEntity(Player caster, LivingEntity target, float power) { if (!validTargetList.canTarget(caster, target)) return false; if (target instanceof Player) { stunPlayer(caster, (Player)target, Math.round(duration * power)); } else { stunEntity(caster, target, Math.round(duration * power)); } return true; } @Override public boolean castAtEntity(LivingEntity target, float power) { if (!validTargetList.canTarget(target)) return false; if (target instanceof Player) { stunPlayer(null, (Player)target, Math.round(duration * power)); } else { stunEntity(null, target, Math.round(duration * power)); } return true; } class StunListener implements Listener { @EventHandler public void onMove(PlayerMoveEvent event) { String playerName = event.getPlayer().getName(); Long until = stunnedPlayersUntil.get(playerName); if (until != null) { if (until.longValue() > System.currentTimeMillis()) { event.setTo(stunnedPlayersLocation.get(playerName)); } else { removePlayer(playerName); } } } @EventHandler public void onInteract(PlayerInteractEvent event) { if (stunnedPlayersUntil.containsKey(event.getPlayer().getName())) { event.setCancelled(true); } } @EventHandler public void onQuit(PlayerQuitEvent event) { String playerName = event.getPlayer().getName(); if (stunnedPlayersUntil.containsKey(playerName)) { removePlayer(playerName); } } @EventHandler public void onDeath(PlayerDeathEvent event) { String playerName = event.getEntity().getName(); if (stunnedPlayersUntil.containsKey(playerName)) { removePlayer(playerName); } } void removePlayer(String playerName) { stunnedPlayersUntil.remove(playerName); stunnedPlayersLocation.remove(playerName); if (stunnedPlayersUntil.size() == 0) { unregisterEvents(this); listener = null; } } } class StunMonitor implements Runnable { @Override public void run() { Iterator<Map.Entry<LivingEntity, Long>> iter = stunnedEntitiesUntil.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<LivingEntity, Long> entry = iter.next(); if (entry.getKey().isValid() && entry.getValue().longValue() > System.currentTimeMillis()) { entry.getKey().teleport(stunnedEntitiesLocation.get(entry.getKey())); } else { iter.remove(); stunnedEntitiesLocation.remove(entry.getKey()); } } if (stunnedEntitiesUntil.size() == 0) { MagicSpells.cancelTask(taskId); taskId = -1; } } } }