package com.nisovin.magicspells.spells.command;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.Spell;
import com.nisovin.magicspells.Spellbook;
import com.nisovin.magicspells.materials.MagicMaterial;
import com.nisovin.magicspells.spells.CommandSpell;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.SpellReagents;
import com.nisovin.magicspells.util.Util;
public class ScrollSpell extends CommandSpell {
private boolean castForFree;
private boolean ignoreCastPerm;
private boolean bypassNormalChecks;
private int defaultUses;
private int maxUses;
private MagicMaterial itemType;
private boolean rightClickCast;
private boolean leftClickCast;
private boolean removeScrollWhenDepleted;
private boolean chargeReagentsForSpellPerCharge;
private boolean requireTeachPerm;
private boolean requireScrollCastPermOnUse;
private boolean textContainsUses;
private String strScrollName;
private String strScrollSubtext;
private String strUsage;
private String strNoSpell;
private String strCantTeach;
private String strOnUse;
private String strUseFail;
private List<String> predefinedScrolls;
private Map<Integer, Spell> predefinedScrollSpells;
private Map<Integer, Integer> predefinedScrollUses;
public ScrollSpell(MagicConfig config, String spellName) {
super(config, spellName);
castForFree = getConfigBoolean("cast-for-free", true);
ignoreCastPerm = getConfigBoolean("ignore-cast-perm", false);
bypassNormalChecks = getConfigBoolean("bypass-normal-checks", false);
defaultUses = getConfigInt("default-uses", 5);
maxUses = getConfigInt("max-uses", 10);
itemType = MagicSpells.getItemNameResolver().resolveItem(getConfigString("item-id", "paper"));
rightClickCast = getConfigBoolean("right-click-cast", true);
leftClickCast = getConfigBoolean("left-click-cast", false);
removeScrollWhenDepleted = getConfigBoolean("remove-scroll-when-depleted", true);
chargeReagentsForSpellPerCharge = getConfigBoolean("charge-reagents-for-spell-per-charge", false);
requireTeachPerm = getConfigBoolean("require-teach-perm", true);
requireScrollCastPermOnUse = getConfigBoolean("require-scroll-cast-perm-on-use", true);
strScrollName = getConfigString("str-scroll-name", "Magic Scroll: %s");
strScrollSubtext = getConfigString("str-scroll-subtext", "Uses remaining: %u");
strUsage = getConfigString("str-usage", "You must hold a single blank paper \nand type /cast scroll <spell> <uses>.");
strNoSpell = getConfigString("str-no-spell", "You do not know a spell by that name.");
strCantTeach = getConfigString("str-cant-teach", "You cannot create a scroll with that spell.");
strOnUse = getConfigString("str-on-use", "Spell Scroll: %s used. %u uses remaining.");
strUseFail = getConfigString("str-use-fail", "Unable to use this scroll right now.");
predefinedScrolls = getConfigStringList("predefined-scrolls", null);
textContainsUses = strScrollName.contains("%u") || strScrollSubtext.contains("%u");
}
@Override
public void initialize() {
super.initialize();
if (predefinedScrolls != null && predefinedScrolls.size() > 0) {
predefinedScrollSpells = new HashMap<Integer, Spell>();
predefinedScrollUses = new HashMap<Integer, Integer>();
for (String s : predefinedScrolls) {
String[] data = s.split(" ");
try {
int id = Integer.parseInt(data[0]);
Spell spell = MagicSpells.getSpellByInternalName(data[1]);
int uses = defaultUses;
if (data.length > 2) uses = Integer.parseInt(data[2]);
if (id > 0 && spell != null) {
predefinedScrollSpells.put(id, spell);
predefinedScrollUses.put(id, uses);
} else {
MagicSpells.error("Scroll spell has invalid predefined scroll: " + s);
}
} catch (Exception e) {
MagicSpells.error("Scroll spell has invalid predefined scroll: " + s);
}
}
}
}
@Override
public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) {
if (state == SpellCastState.NORMAL) {
if (args == null || args.length == 0) {
// fail -- no args
sendMessage(player, strUsage);
return PostCastAction.ALREADY_HANDLED;
}
// get item in hand
ItemStack inHand = player.getItemInHand();
if (inHand.getAmount() != 1 || !itemType.equals(inHand)) {
// fail -- incorrect item in hand
sendMessage(player, strUsage);
return PostCastAction.ALREADY_HANDLED;
}
// get spell
Spell spell = MagicSpells.getSpellByInGameName(args[0]);
Spellbook spellbook = MagicSpells.getSpellbook(player);
if (spell == null || spellbook == null || !spellbook.hasSpell(spell)) {
// fail -- no such spell
sendMessage(player, strNoSpell);
return PostCastAction.ALREADY_HANDLED;
} else if (requireTeachPerm && !spellbook.canTeach(spell)) {
sendMessage(player, strCantTeach);
return PostCastAction.ALREADY_HANDLED;
}
// get uses
int uses = defaultUses;
if (args.length > 1 && args[1].matches("^-?[0-9]+$")) {
uses = Integer.parseInt(args[1]);
}
if (uses > maxUses || (maxUses > 0 && uses <= 0)) {
uses = maxUses;
}
// get additional reagent cost
if (chargeReagentsForSpellPerCharge && uses > 0) {
SpellReagents reagents = spell.getReagents().multiply(uses);
if (!hasReagents(player, reagents)) {
// missing reagents
sendMessage(player, strMissingReagents);
return PostCastAction.ALREADY_HANDLED;
} else {
// has reagents, so just remove them
removeReagents(player, reagents);
}
}
// create scroll
inHand = createScroll(spell, uses, inHand);
player.setItemInHand(inHand);
// done
sendMessage(player, formatMessage(strCastSelf, "%s", spell.getName()));
return PostCastAction.NO_MESSAGES;
}
return PostCastAction.HANDLE_NORMALLY;
}
public ItemStack createScroll(Spell spell, int uses, ItemStack item) {
if (item == null) {
item = itemType.toItemStack(1);
}
item.setDurability((short)0);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', strScrollName.replace("%s", spell.getName()).replace("%u", (uses>=0?uses+"":"many"))));
if (strScrollSubtext != null && !strScrollSubtext.isEmpty()) {
List<String> lore = new ArrayList<String>();
lore.add(ChatColor.translateAlternateColorCodes('&', strScrollSubtext.replace("%s", spell.getName()).replace("%u", (uses>=0?uses+"":"many"))));
meta.setLore(lore);
}
item.setItemMeta(meta);
Util.setLoreData(item, internalName + ":" + spell.getInternalName() + (uses > 0 ? "," + uses : ""));
item = MagicSpells.getVolatileCodeHandler().addFakeEnchantment(item);
return item;
}
@Override
public boolean castFromConsole(CommandSender sender, String[] args) {
return false;
}
@Override
public List<String> tabComplete(CommandSender sender, String partial) {
String[] args = Util.splitParams(partial);
if (args.length == 1) {
return tabCompleteSpellName(sender, args[0]);
} else {
return null;
}
}
private String getSpellDataFromScroll(ItemStack item) {
String loreData = Util.getLoreData(item);
if (loreData != null && loreData.startsWith(internalName + ":")) {
return loreData.replace(internalName + ":", "");
}
return null;
}
@EventHandler(priority=EventPriority.MONITOR)
public void onPlayerInteract(PlayerInteractEvent event) {
if ((rightClickCast && (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK)) ||
(leftClickCast && (event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK))) {
Player player = event.getPlayer();
ItemStack inHand = player.getItemInHand();
if (itemType.getMaterial() != inHand.getType() || inHand.getAmount() > 1) return;
// check for predefined scroll
if (inHand.getDurability() > 0 && predefinedScrollSpells != null) {
Spell spell = predefinedScrollSpells.get(Integer.valueOf(inHand.getDurability()));
if (spell != null) {
int uses = predefinedScrollUses.get(Integer.valueOf(inHand.getDurability()));
inHand = createScroll(spell, uses, inHand);
player.setItemInHand(inHand);
}
}
// get scroll data (spell and uses)
String scrollDataString = getSpellDataFromScroll(inHand);
if (scrollDataString == null || scrollDataString.isEmpty()) return;
String[] scrollData = scrollDataString.split(",");
Spell spell = MagicSpells.getSpellByInternalName(scrollData[0]);
if (spell == null) return;
int uses = 0;
if (scrollData.length > 1 && scrollData[1].matches("^[0-9]+$")) {
uses = Integer.parseInt(scrollData[1]);
}
// check for permission
if (requireScrollCastPermOnUse && !MagicSpells.getSpellbook(player).canCast(this)) {
sendMessage(player, strUseFail);
return;
}
// cast spell
if (ignoreCastPerm && !player.hasPermission("magicspells.cast." + spell.getInternalName())) {
player.addAttachment(MagicSpells.plugin, "magicspells.cast." + spell.getInternalName(), true, 1);
}
if (castForFree && !player.hasPermission("magicspells.noreagents")) {
player.addAttachment(MagicSpells.plugin, "magicspells.noreagents", true, 1);
}
SpellCastState state;
PostCastAction action;
if (bypassNormalChecks) {
state = SpellCastState.NORMAL;
action = spell.castSpell(player, SpellCastState.NORMAL, 1.0F, null);
} else {
SpellCastResult result = spell.cast(player);
state = result.state;
action = result.action;
}
if (state == SpellCastState.NORMAL && action != PostCastAction.ALREADY_HANDLED) {
// remove use
if (uses > 0) {
uses -= 1;
if (uses > 0) {
inHand = createScroll(spell, uses, inHand);
if (textContainsUses) {
player.setItemInHand(inHand);
}
} else {
if (removeScrollWhenDepleted) {
player.setItemInHand(null);
} else {
player.setItemInHand(itemType.toItemStack(1));
}
}
}
// send msg
sendMessage(player, formatMessage(strOnUse, "%s", spell.getName(), "%u", (uses>=0?uses+"":"many")));
}
}
}
@EventHandler
public void onItemSwitch(PlayerItemHeldEvent event) {
Player player = event.getPlayer();
ItemStack inHand = player.getInventory().getItem(event.getNewSlot());
if (inHand == null || inHand.getType() != itemType.getMaterial()) return;
// check for predefined scroll
if (inHand.getDurability() > 0 && predefinedScrollSpells != null) {
Spell spell = predefinedScrollSpells.get(Integer.valueOf(inHand.getDurability()));
if (spell != null) {
int uses = predefinedScrollUses.get(Integer.valueOf(inHand.getDurability()));
inHand = createScroll(spell, uses, inHand);
player.getInventory().setItem(event.getNewSlot(), inHand);
}
}
}
}