package com.nisovin.magicspells.spells.targeted; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Bukkit; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import com.nisovin.magicspells.MagicSpells; import com.nisovin.magicspells.Spell; import com.nisovin.magicspells.events.SpellCastEvent; 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; import com.nisovin.magicspells.util.ValidTargetList; public class SilenceSpell extends TargetedSpell implements TargetedEntitySpell { private boolean preventCast; private boolean preventChat; private boolean preventCommands; private int duration; private List<String> allowedSpellNames; private Set<Spell> allowedSpells; private List<String> disallowedSpellNames; private Set<Spell> disallowedSpells; private String strSilenced; private Map<String,Unsilencer> silenced; public SilenceSpell(MagicConfig config, String spellName) { super(config, spellName); preventCast = getConfigBoolean("prevent-cast", true); preventChat = getConfigBoolean("prevent-chat", false); preventCommands = getConfigBoolean("prevent-commands", false); duration = getConfigInt("duration", 200); allowedSpellNames = getConfigStringList("allowed-spells", null); disallowedSpellNames = getConfigStringList("disallowed-spells", null); strSilenced = getConfigString("str-silenced", "You are silenced!"); if (preventChat) { silenced = new ConcurrentHashMap<String, Unsilencer>(); } else { silenced = new HashMap<String, Unsilencer>(); } validTargetList = new ValidTargetList(true, false); } @Override public void initialize() { super.initialize(); if (allowedSpellNames != null && allowedSpellNames.size() > 0) { allowedSpells = new HashSet<Spell>(); for (String spellName : allowedSpellNames) { Spell spell = MagicSpells.getSpellByInternalName(spellName); if (spell != null) { allowedSpells.add(spell); } else { MagicSpells.error("Invalid allowed spell specified on silence spell '" + this.internalName + "': '" + spellName + "'"); } } allowedSpellNames.clear(); } allowedSpellNames = null; if (disallowedSpellNames != null && disallowedSpellNames.size() > 0) { disallowedSpells = new HashSet<Spell>(); for (String spellName : disallowedSpellNames) { Spell spell = MagicSpells.getSpellByInternalName(spellName); if (spell != null) { disallowedSpells.add(spell); } else { MagicSpells.error("Invalid disallowed spell specified on silence spell '" + this.internalName + "': '" + spellName + "'"); } } disallowedSpellNames.clear(); } disallowedSpellNames = null; if (preventCast) { registerEvents(new CastListener()); } if (preventChat) { registerEvents(new ChatListener()); } if (preventCommands) { registerEvents(new CommandListener()); } } @Override public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) { if (state == SpellCastState.NORMAL) { TargetInfo<Player> target = getTargetedPlayer(player, power); if (target == null) { return noTarget(player); } // silence player silence(target.getTarget(), target.getPower()); playSpellEffects(player, target.getTarget()); sendMessages(player, target.getTarget()); return PostCastAction.NO_MESSAGES; } return PostCastAction.HANDLE_NORMALLY; } private void silence(Player player, float power) { // handle previous silence Unsilencer u = silenced.get(player.getName()); if (u != null) { u.cancel(); } // silence now silenced.put(player.getName(), new Unsilencer(player, Math.round(duration * power))); } @Override public boolean castAtEntity(Player caster, LivingEntity target, float power) { if (target instanceof Player) { silence((Player)target, power); playSpellEffects(caster, target); return true; } else { return false; } } @Override public boolean castAtEntity(LivingEntity target, float power) { if (target instanceof Player) { silence((Player)target, power); playSpellEffects(EffectPosition.TARGET, target); return true; } else { return false; } } public class CastListener implements Listener { @EventHandler(ignoreCancelled=true) public void onSpellCast(final SpellCastEvent event) { if ( event.getCaster() != null && silenced.containsKey(event.getCaster().getName()) && (allowedSpells == null || !allowedSpells.contains(event.getSpell())) && (disallowedSpells == null || disallowedSpells.contains(event.getSpell())) ) { event.setCancelled(true); Bukkit.getScheduler().scheduleSyncDelayedTask(MagicSpells.plugin, new Runnable() { public void run() { sendMessage(event.getCaster(), strSilenced); } }); } } } public class ChatListener implements Listener { @EventHandler(ignoreCancelled=true) public void onChat(AsyncPlayerChatEvent event) { if (silenced.containsKey(event.getPlayer().getName())) { event.setCancelled(true); sendMessage(event.getPlayer(), strSilenced); } } } public class CommandListener implements Listener { @EventHandler(ignoreCancelled=true) public void onCommand(PlayerCommandPreprocessEvent event) { if (silenced.containsKey(event.getPlayer().getName())) { event.setCancelled(true); sendMessage(event.getPlayer(), strSilenced); } } } public class Unsilencer implements Runnable { private String playerName; private boolean canceled = false; private int taskId = -1; public Unsilencer(Player player, int delay) { this.playerName = player.getName(); taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(MagicSpells.plugin, this, delay); } @Override public void run() { if (!canceled) { silenced.remove(playerName); } } public void cancel() { canceled = true; if (taskId > 0) { Bukkit.getScheduler().cancelTask(taskId); } } } }