package com.nisovin.magicspells.spells.targeted; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.DyeColor; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.entity.Villager.Profession; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.event.player.PlayerQuitEvent; import com.nisovin.magicspells.MagicSpells; import com.nisovin.magicspells.events.SpellCastedEvent; import com.nisovin.magicspells.spelleffects.EffectPosition; import com.nisovin.magicspells.spells.TargetedEntitySpell; import com.nisovin.magicspells.spells.TargetedSpell; import com.nisovin.magicspells.util.DisguiseManager; import com.nisovin.magicspells.util.EntityData; import com.nisovin.magicspells.util.MagicConfig; import com.nisovin.magicspells.util.TargetInfo; public class DisguiseSpell extends TargetedSpell implements TargetedEntitySpell { static DisguiseManager manager; private DisguiseSpell thisSpell; private EntityData entityData; private boolean showPlayerName = false; private String nameplateText = ""; private String uuid = ""; private String skin = ""; private String skinSig = ""; private boolean alwaysShowNameplate = true; private boolean preventPickups = false; private boolean friendlyMobs = true; private boolean ridingBoat = false; private boolean undisguiseOnDeath = true; private boolean undisguiseOnLogout = false; private boolean undisguiseOnCast = false; private boolean undisguiseOnGiveDamage = false; private boolean undisguiseOnTakeDamage = false; private boolean disguiseSelf = false; private int duration; private boolean toggle; private String strFade; private Map<String, Disguise> disguised = new HashMap<String, Disguise>(); public DisguiseSpell(MagicConfig config, String spellName) { super(config, spellName); thisSpell = this; if (manager == null) { try { manager = MagicSpells.getVolatileCodeHandler().getDisguiseManager(config); } catch (Exception e) { manager = null; } if (manager == null) { MagicSpells.error("DisguiseManager could not be created!"); return; } } manager.registerSpell(this); String type = getConfigString("entity-type", "zombie"); entityData = new EntityData(type); showPlayerName = getConfigBoolean("show-player-name", false); nameplateText = ChatColor.translateAlternateColorCodes('&', getConfigString("nameplate-text", "")); uuid = getConfigString("uuid", ""); if (configKeyExists("skin")) { String skinName = getConfigString("skin", "skin"); File folder = new File(MagicSpells.getInstance().getDataFolder(), "disguiseskins"); if (folder.exists()) { try { File file = new File(folder, skinName + ".skin.txt"); if (file.exists()) { BufferedReader reader = new BufferedReader(new FileReader(file)); skin = reader.readLine(); reader.close(); } file = new File(folder, skinName + ".sig.txt"); if (file.exists()) { BufferedReader reader = new BufferedReader(new FileReader(file)); skinSig = reader.readLine(); reader.close(); } } catch (Exception e) { MagicSpells.handleException(e); } } } alwaysShowNameplate = getConfigBoolean("always-show-nameplate", true); preventPickups = getConfigBoolean("prevent-pickups", true); friendlyMobs = getConfigBoolean("friendly-mobs", true); ridingBoat = getConfigBoolean("riding-boat", false); undisguiseOnDeath = getConfigBoolean("undisguise-on-death", true); undisguiseOnLogout = getConfigBoolean("undisguise-on-logout", false); undisguiseOnCast = getConfigBoolean("undisguise-on-cast", false); undisguiseOnGiveDamage = getConfigBoolean("undisguise-on-give-damage", false); undisguiseOnTakeDamage = getConfigBoolean("undisguise-on-take-damage", false); disguiseSelf = getConfigBoolean("disguise-self", false); duration = getConfigInt("duration", 0); toggle = getConfigBoolean("toggle", false); targetSelf = getConfigBoolean("target-self", true); strFade = getConfigString("str-fade", ""); if (entityData.getType() == null) { MagicSpells.error("Invalid entity-type specified for disguise spell '" + spellName + "'"); } } @Override public void initialize() { if (manager == null) return; super.initialize(); if (undisguiseOnCast) { registerEvents(new CastListener()); } if (undisguiseOnGiveDamage || undisguiseOnTakeDamage) { registerEvents(new DamageListener()); } } @Override public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) { if (manager == null) return PostCastAction.ALREADY_HANDLED; if (state == SpellCastState.NORMAL) { Disguise oldDisguise = disguised.remove(player.getName().toLowerCase()); manager.removeDisguise(player); if (oldDisguise != null && toggle) { sendMessage(player, strFade); return PostCastAction.ALREADY_HANDLED; } TargetInfo<Player> target = getTargetPlayer(player, power); if (target != null) { disguise(target.getTarget()); sendMessages(player, target.getTarget()); playSpellEffects(EffectPosition.CASTER, player); return PostCastAction.NO_MESSAGES; } else { return noTarget(player); } } return PostCastAction.HANDLE_NORMALLY; } private void disguise(Player player) { String nameplate = nameplateText; if (showPlayerName) nameplate = player.getDisplayName(); PlayerDisguiseData playerDisguiseData = new PlayerDisguiseData((uuid.isEmpty() ? UUID.randomUUID().toString() : uuid), skin, skinSig); Disguise disguise = new Disguise(player, entityData.getType(), nameplate, playerDisguiseData, alwaysShowNameplate, disguiseSelf, ridingBoat, entityData.getFlag(), entityData.getVar1(), entityData.getVar2(), entityData.getVar3(), duration, this); manager.addDisguise(player, disguise); disguised.put(player.getName().toLowerCase(), disguise); playSpellEffects(EffectPosition.TARGET, player); } public void undisguise(Player player) { Disguise disguise = disguised.remove(player.getName().toLowerCase()); if (disguise != null) { disguise.cancelDuration(); sendMessage(player, strFade); playSpellEffects(EffectPosition.DISABLED, player); } } @Override public boolean castAtEntity(Player player, LivingEntity target, float power) { if (target instanceof Player) { disguise((Player)target); return true; } return false; } @Override public boolean castAtEntity(LivingEntity target, float power) { if (target instanceof Player) { disguise((Player)target); return true; } return false; } @EventHandler public void onPickup(PlayerPickupItemEvent event) { if (preventPickups && disguised.containsKey(event.getPlayer().getName().toLowerCase())) { event.setCancelled(true); } } @EventHandler public void onDeath(PlayerDeathEvent event) { if (undisguiseOnDeath && disguised.containsKey(event.getEntity().getName().toLowerCase())) { manager.removeDisguise(event.getEntity(), entityData.getType() == EntityType.PLAYER); } } @EventHandler public void onQuit(PlayerQuitEvent event) { if (undisguiseOnLogout && disguised.containsKey(event.getPlayer().getName().toLowerCase())) { manager.removeDisguise(event.getPlayer(), entityData.getType() == EntityType.PLAYER); } } @EventHandler public void onTarget(EntityTargetEvent event) { if (friendlyMobs && event.getTarget() != null && event.getTarget() instanceof Player && disguised.containsKey(((Player)event.getTarget()).getName().toLowerCase())) { event.setCancelled(true); } } class CastListener implements Listener { @EventHandler void onSpellCast(SpellCastedEvent event) { if (event.getSpell() != thisSpell && disguised.containsKey(event.getCaster().getName().toLowerCase())) { manager.removeDisguise(event.getCaster()); } } } class DamageListener implements Listener { @EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true) void onDamage(EntityDamageEvent event) { if (undisguiseOnTakeDamage && event.getEntity() instanceof Player && disguised.containsKey(((Player)event.getEntity()).getName().toLowerCase())) { manager.removeDisguise((Player)event.getEntity()); } if (undisguiseOnGiveDamage && event instanceof EntityDamageByEntityEvent) { Entity e = ((EntityDamageByEntityEvent)event).getDamager(); if (e instanceof Player) { if (disguised.containsKey(((Player)e).getName().toLowerCase())) { manager.removeDisguise((Player)e); } } else if (e instanceof Projectile && ((Projectile)e).getShooter() instanceof Player) { Player shooter = (Player)((Projectile)e).getShooter(); if (disguised.containsKey(shooter.getName().toLowerCase())) { manager.removeDisguise(shooter); } } } } } public static DisguiseManager getDisguiseManager() { return manager; } @Override public void turnOff() { if (manager != null) { for (String name : new ArrayList<String>(disguised.keySet())) { Player player = Bukkit.getPlayerExact(name); if (player != null) { manager.removeDisguise(player, false); } } manager.unregisterSpell(this); if (manager.registeredSpellsCount() == 0) { manager.destroy(); manager = null; } } } public class Disguise { private Player player; private EntityType entityType; private String nameplateText; private PlayerDisguiseData playerDisguiseData; private boolean alwaysShowNameplate; private boolean disguiseSelf; private boolean ridingBoat; private boolean flag; private int var1; private int var2; private int var3; private DisguiseSpell spell; private int taskId; public Disguise(Player player, EntityType entityType, String nameplateText, PlayerDisguiseData playerDisguiseData, boolean alwaysShowNameplate, boolean disguiseSelf, boolean ridingBoat, boolean flag, int var1, int var2, int var3, int duration, DisguiseSpell spell) { this.player = player; this.entityType = entityType; this.nameplateText = nameplateText; this.playerDisguiseData = playerDisguiseData; this.alwaysShowNameplate = alwaysShowNameplate; this.disguiseSelf = disguiseSelf; this.ridingBoat = ridingBoat; this.flag = flag; this.var1 = var1; this.var2 = var2; this.var3 = var3; if (duration > 0) { startDuration(duration); } this.spell = spell; } public Player getPlayer() { return player; } public EntityType getEntityType() { return entityType; } public String getNameplateText() { return nameplateText; } public PlayerDisguiseData getPlayerDisguiseData() { return playerDisguiseData; } public boolean alwaysShowNameplate() { return alwaysShowNameplate; } public boolean disguiseSelf() { return disguiseSelf; } public boolean isRidingBoat() { return ridingBoat; } public boolean getFlag() { return flag; } public int getVar1() { return var1; } public int getVar2() { return var2; } public int getVar3() { return var3; } private void startDuration(int duration) { taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(MagicSpells.plugin, new Runnable() { public void run() { DisguiseSpell.manager.removeDisguise(player); } }, duration); } public void cancelDuration() { if (taskId > 0) { Bukkit.getScheduler().cancelTask(taskId); taskId = 0; } } public DisguiseSpell getSpell() { return spell; } } public class PlayerDisguiseData { public String uuid; public String skin; public String sig; public PlayerDisguiseData(String uuid, String skin, String sig) { this.uuid = uuid; this.skin = skin; this.sig = sig; } public PlayerDisguiseData clone() { return new PlayerDisguiseData(uuid, skin, sig); } } }