diff --git a/pom.xml b/pom.xml index 32ddae5..858cdef 100644 --- a/pom.xml +++ b/pom.xml @@ -14,14 +14,14 @@ org.spigotmc spigot-api - 1.10-R0.1-SNAPSHOT + 1.11.2-R0.1-SNAPSHOT provided org.bukkit - bukkit - 1.10-R0.1-SNAPSHOT + craftbukkit + 1.11.2-R0.1-SNAPSHOT provided diff --git a/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java b/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java index 46f6213..ce7e95d 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/ArmoredElytra.java @@ -15,6 +15,7 @@ public class ArmoredElytra extends EnchantPlugin implements Listener { Bukkit.getPluginManager().registerEvents(new EventHandlers(this), this); } + // TODO: Remove this after updating elytras on my server. @Override public void registerEnchantments() { EnchantmentAPI.registerCustomEnchantment(new DiamondArmor()); diff --git a/src/main/java/nl/pim16aap2/armoredElytra/EventHandlers.java b/src/main/java/nl/pim16aap2/armoredElytra/EventHandlers.java index e8d2843..02b77be 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/EventHandlers.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/EventHandlers.java @@ -1,10 +1,11 @@ package nl.pim16aap2.armoredElytra; +import java.util.Arrays; import java.util.Map; import java.util.Random; import org.bukkit.Material; -import org.bukkit.attribute.Attribute; +import org.bukkit.craftbukkit.v1_11_R1.inventory.CraftItemStack; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -15,20 +16,38 @@ import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.AnvilInventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.scheduler.BukkitRunnable; +import net.minecraft.server.v1_11_R1.*; + import com.rit.sucy.EnchantmentAPI; import net.md_5.bungee.api.ChatColor; public class EventHandlers implements Listener { + private int DIAMONDS_TO_FULL = 3; + private int LEATHER_TO_FULL = 4; private final ArmoredElytra plugin; + private String[] allowedEnchantments = {"DURABILITY", + "PROTECTION_FIRE", + "PROTECTION_EXPLOSIONS", + "PROTECTION_PROJECTILE", + "PROTECTION_ENVIRONMENTAL", + "DIAMOND_ARMOR_ITEMS", + "THORNS"}; + private String[] specialEnchantments = {"MENDING", + "VANISHING_CURSE", + "BINDING_CURSE"}; public EventHandlers(ArmoredElytra plugin) { this.plugin = plugin; } + + // Clear the anvil's inventory (destroy all the items in all 3 slots (second slot is not emptied, when repairing you can safely give multiple items)). public void cleanAnvil(AnvilInventory anvilInventory){ anvilInventory.getItem(0).setAmount(0); @@ -36,13 +55,105 @@ public class EventHandlers implements Listener { anvilInventory.getItem(2).setAmount(0); } - // Check if the elytra being checked is an armored one. - public boolean isArmoredElytra(ItemStack elytra) { - if (EnchantmentAPI.itemHasEnchantment(elytra, "Diamond Armor Tier")) { - return true; + + + // Check if the enchantment is allowed on elytras. + public boolean isAllowedEnchantment(Enchantment enchant) { + for (String s : allowedEnchantments) { + if (Enchantment.getByName(s).equals(enchant)) { + return true; + } } return false; - } + } + + + + // Check if the enchantment is "special", i.e. cannot be enchanted by the EnchantmentAPI. + public boolean isSpecialEnchantment(Enchantment enchant) { + for (String s : specialEnchantments) { + if (Enchantment.getByName(s).equals(enchant)) { + return true; + } + } + return false; + } + + + + // Check if the elytra being checked is an armored one. + public boolean isArmoredElytra(ItemStack elytra) { + if (elytra.hasItemMeta() && elytra.getType() == Material.ELYTRA) + if (elytra.getItemMeta().hasLore()) + if (elytra.getItemMeta().getLore().toString().equals("[This is an armored Elytra.]")) { + return true; + } + return false; + } + + + + // Copy enchants of 2 items to one item. + public ItemStack addEnchants(ItemStack itemOne, ItemStack itemTwo, Player p) { + // Create the resulting item and apply the diamond armor tier enchantment to it. + ItemStack result = itemOne.clone(); + + // Get the enchantments of the first and second item in the anvil. + Map enchantments0 = itemOne.getEnchantments(); + Map enchantments1 = itemTwo.getEnchantments(); + // Enchants from enchanted books have to be access in a different way. + if (itemTwo.getType() == Material.ENCHANTED_BOOK && isArmoredElytra(itemOne)) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta)itemTwo.getItemMeta(); + enchantments1 = meta.getStoredEnchants(); + } + + // Copy enchantments from item1 to result. + if (enchantments1!=null) { + for (Map.Entry entry : enchantments1.entrySet()) { + if (isSpecialEnchantment(entry.getKey()) && !result.containsEnchantment(entry.getKey())) { + result.addEnchantment(entry.getKey(), entry.getValue()); + } else if (isAllowedEnchantment(entry.getKey())) { + int enchantLevel = entry.getValue(); + // If item0 and item1 both have the same enchantment at the same level, result has level+1. + // If item0 and item1 both have the same enchantment at different levels, give the highest level to result. + if (enchantments0 != null) { + for (Map.Entry rentry : enchantments0.entrySet()) { + if (entry.getKey().getName() == rentry.getKey().getName()) { + if (entry.getValue() == rentry.getValue() && entry.getValue() < entry.getKey().getMaxLevel()) { + enchantLevel = entry.getValue()+1; + } else if (entry.getValue() < rentry.getValue()) { + enchantLevel = rentry.getValue(); + } + } + } + } + EnchantmentAPI.getEnchantment(entry.getKey().getName()).addToItem(result, enchantLevel); + } else { + p.sendMessage(ChatColor.RED+"This enchantment is not allowed on this item!"); + } + } + } + + return result; + } + + + + // Copy enchants of 2 items to one item. + public ItemStack repairItem(ItemStack one, ItemStack two) { + // Create the resulting item. + ItemStack result = one.clone(); + + int mult = two.getType() == Material.DIAMOND ? 100/DIAMONDS_TO_FULL : 100/LEATHER_TO_FULL; + int maxDurability = one.getType().getMaxDurability(); + int durability = one.getDurability(); + int newDurability = (durability - (int) (maxDurability*mult)); + result.setDurability((short) (newDurability >= 0 ? newDurability : 0) ); + + return result; + } + + // Handle the anvil related parts. @EventHandler @@ -65,118 +176,89 @@ public class EventHandlers implements Listener { // Clean the anvil's inventory after transferring the items. cleanAnvil(anvilInventory); } - } + } new BukkitRunnable() { @Override public void run() { // Check if there are items in both input slots. - if (anvilInventory.getItem(0) != null && anvilInventory.getItem(1) != null) { + if (anvilInventory.getItem(0) != null && anvilInventory.getItem(1) != null) { // Check if the first input slot contains an elytra. if (anvilInventory.getItem(0).getType() == Material.ELYTRA) { + ItemStack result = null; // Check if the second input slot contains a diamond chestplate. - if (anvilInventory.getItem(1).getType() == Material.DIAMOND_CHESTPLATE) { - - // Get the enchantments of the first and second item in the anvil. - Map enchantments0 = anvilInventory.getItem(0).getEnchantments(); - Map enchantments1 = anvilInventory.getItem(1).getEnchantments(); - - // Create the resulting item and apply the diamond armor tier enchantment to it. - ItemStack result = new ItemStack(Material.ELYTRA, 1); - EnchantmentAPI.getEnchantment("Diamond Armor Tier").addToItem(result, 1); - - // Copy enchantments from item0 to result. - if (enchantments0!=null) { - for (Map.Entry entry : enchantments0.entrySet()) { - if (entry.getKey().getName().equals("MENDING") || entry.getKey().getName().equals("VANISHING_CURSE") || entry.getKey().getName().equals("VANISHING_CURSE")) { - result.addEnchantment(entry.getKey(), 1); - } else { - EnchantmentAPI.getEnchantment(entry.getKey().getName()).addToItem(result, 1); - } - } - } - // Copy enchantments from item1 to result. - if (enchantments1!=null) { - for (Map.Entry entry : enchantments1.entrySet()) { - if (entry.getKey().getName().equals("MENDING") || entry.getKey().getName().equals("VANISHING_CURSE") || entry.getKey().getName().equals("VANISHING_CURSE")) - result.addEnchantment(entry.getKey(), 1); - else { - Map resultEnchantments = result.getEnchantments(); - int enchantLevel = entry.getValue(); - // If item0 and item1 both have the same enchantment at the same level, result has level+1. - // If item0 and item1 both have the same enchantment at different levels, give the highest level to result. - if (resultEnchantments != null) { - for (Map.Entry rentry : resultEnchantments.entrySet()) { - if (entry.getKey().getName() == rentry.getKey().getName()) { - if (entry.getValue() == rentry.getValue() && entry.getValue()<5) { - enchantLevel = entry.getValue()+1; - } else if (entry.getValue() < rentry.getValue()) { - enchantLevel = rentry.getValue(); - } - } - } - } - if (!entry.getKey().getName().equals("MENDING") && !entry.getKey().getName().equals("VANISHING_CURSE") && !entry.getKey().getName().equals("VANISHING_CURSE")) - EnchantmentAPI.getEnchantment(entry.getKey().getName()).addToItem(result, enchantLevel); - } - } - } - // Resulting item will have full durability. - result.setDurability((short) 0); - // Add resulting item in the second slot of the anvil. - anvilInventory.setItem(2, result); - + if (anvilInventory.getItem(1).getType() == Material.DIAMOND_CHESTPLATE || + (anvilInventory.getItem(1).getType() == Material.ENCHANTED_BOOK && isArmoredElytra(anvilInventory.getItem(0)))) { + // Combine the enchantments of the two items in the input slots. + result = addEnchants(anvilInventory.getItem(0), anvilInventory.getItem(1), p); + if (anvilInventory.getItem(1).getType() == Material.DIAMOND_CHESTPLATE) { + result.setDurability((short)0); + } + } // If the player tries to repair an armored elytra with diamonds or a regular elytra with leather, repair 52% or 26%. - } else if ((anvilInventory.getItem(1).getType() == Material.LEATHER && !isArmoredElytra(anvilInventory.getItem(0))) || - (anvilInventory.getItem(1).getType() == Material.DIAMOND && isArmoredElytra(anvilInventory.getItem(0)))) { - int mult = anvilInventory.getItem(1).getType() == Material.DIAMOND ? 2 : 1; - ItemStack result = anvilInventory.getItem(0).clone(); - int maxDurability = anvilInventory.getItem(0).getType().getMaxDurability(); - int durability = anvilInventory.getItem(0).getDurability(); - int newDurability = (durability - (int) (maxDurability*0.26*mult)); - result.setDurability((short) (newDurability >= 0 ? newDurability : 0) ); - // Add resulting item in the second slot of the anvil. - anvilInventory.setItem(2, result); - + else if ((anvilInventory.getItem(1).getType() == Material.LEATHER && !isArmoredElytra(anvilInventory.getItem(0))) || + (anvilInventory.getItem(1).getType() == Material.DIAMOND && isArmoredElytra(anvilInventory.getItem(0)))) { + // Repair the item in the first input slot with items from the second input slot. + result = repairItem(anvilInventory.getItem(0), anvilInventory.getItem(1)); + } // Otherwise, remove the item in the result slot (slot2). - } else { + else { if (anvilInventory.getItem(2)!=null) { anvilInventory.getItem(2).setAmount(0); } } - // update inventory to show changes made to the anvil's inventory. - p.updateInventory(); + // Put the created item in the second slot of the anvil. + if (result!=null) { + if (anvilInventory.getItem(1).getType() == Material.DIAMOND_CHESTPLATE/* || isArmoredElytra(anvilInventory.getItem(0))*/) { + ItemMeta itemmeta = result.getItemMeta(); + itemmeta.setDisplayName(ChatColor.AQUA+"Armored Elytra"); + itemmeta.setLore(Arrays.asList("This is an armored Elytra.")); + result.setItemMeta(itemmeta); + net.minecraft.server.v1_11_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(result); + NBTTagCompound compound = (nmsStack.hasTag()) ? nmsStack.getTag() : new NBTTagCompound(); + NBTTagList modifiers = new NBTTagList(); + NBTTagCompound armor = new NBTTagCompound(); + armor.set("AttributeName", new NBTTagString("generic.armor")); + armor.set("Name", new NBTTagString("generic.armor")); + armor.set("Amount", new NBTTagInt(8)); + armor.set("Operation", new NBTTagInt(0)); + armor.set("UUIDLeast", new NBTTagInt(894654)); + armor.set("UUIDMost", new NBTTagInt(2872)); + armor.set("Slot", new NBTTagString("chest")); + modifiers.add(armor); + NBTTagCompound armorTough = new NBTTagCompound(); + armorTough.set("AttributeName", new NBTTagString("generic.armorToughness")); + armorTough.set("Name", new NBTTagString("generic.armorToughness")); + armorTough.set("Amount", new NBTTagInt(2)); + armorTough.set("Operation", new NBTTagInt(0)); + armorTough.set("UUIDLeast", new NBTTagInt(894654)); + armorTough.set("UUIDMost", new NBTTagInt(2872)); + armorTough.set("Slot", new NBTTagString("chest")); + modifiers.add(armorTough); + compound.set("AttributeModifiers", modifiers); + result = CraftItemStack.asBukkitCopy(nmsStack); + } + anvilInventory.setItem(2, result); + } } - } + // Super ugly way of making sure that when applying enchantments from an enchanted book to an elytra, the result has a higher chance of showing up. + if (anvilInventory.getItem(1).getType() == Material.ENCHANTED_BOOK) { + p.updateInventory(); + p.updateInventory(); + p.updateInventory(); + p.updateInventory(); + p.updateInventory(); + p.updateInventory(); + p.sendMessage(ChatColor.GREEN+"Combining enchanted books with elytras IS possible, but sometimes you have to remove the book and put it back a few times."); + } + } + p.updateInventory(); } - // Do all this with a slight delay, so the resulting item shows up in the final slot properly. }.runTaskLater(this.plugin, 1); } } } - // Calculate the toughness of the player's armor. 2 Points per part of diamond armor (and 2 for armored elytra's... duh...). - public double getArmorToughness(Player p) { - double toughness = 0; - if (p.getInventory().getBoots()!=null) - if (p.getInventory().getBoots().getType() == Material.DIAMOND_BOOTS) { - toughness+=2; - } - if (p.getInventory().getHelmet()!=null) - if (p.getInventory().getHelmet().getType() == Material.DIAMOND_HELMET) { - toughness+=2; - } - if (p.getInventory().getLeggings()!=null) - if (p.getInventory().getLeggings().getType() == Material.DIAMOND_LEGGINGS) { - toughness+=2; - } - if (p.getInventory().getChestplate()!=null) - if (p.getInventory().getChestplate().getType() == Material.DIAMOND_CHESTPLATE || - (p.getInventory().getChestplate().getType() == Material.ELYTRA && isArmoredElytra(p.getInventory().getChestplate()))) { - toughness+=2; - } - return toughness; - } // Because the armored elytra doesn't actually give any armor, the damage received by players wearing an armored elytra is calculated here. @@ -187,26 +269,12 @@ public class EventHandlers implements Listener { if (p.getInventory().getChestplate()!=null) { if (p.getInventory().getChestplate().getType() == Material.ELYTRA && isArmoredElytra(p.getInventory().getChestplate())) { DamageCause cause = e.getCause(); - if (cause!=DamageCause.DROWNING && cause!=DamageCause.LIGHTNING && cause!=DamageCause.STARVATION && cause!=DamageCause.SUFFOCATION && cause!=DamageCause.FALL && cause!=DamageCause.SUICIDE && cause!=DamageCause.FIRE_TICK && cause!=DamageCause.FIRE && cause!=DamageCause.FLY_INTO_WALL && cause!=DamageCause.POISON) { - double damage = e.getDamage(); - // Get the defense points of the player (armor rating), then add 8 (value of diamond chestplate). - double defensePoints = p.getAttribute(Attribute.GENERIC_ARMOR).getValue()+8; - double toughness = getArmorToughness(p); - // Calculate new damage based on formula found on the wiki. - double newDamage = e.getDamage() * (1-Math.min(20, Math.max(defensePoints/5, defensePoints-e.getDamage()/(2+toughness/4)))/25); - - e.setDamage(EntityDamageEvent.DamageModifier.ABSORPTION, 0); - e.setDamage(EntityDamageEvent.DamageModifier.ARMOR, 0); - e.setDamage(EntityDamageEvent.DamageModifier.BLOCKING, 0); -// e.setDamage(EntityDamageEvent.DamageModifier.HARD_HAT, 0); - e.setDamage(EntityDamageEvent.DamageModifier.MAGIC, 0); - e.setDamage(EntityDamageEvent.DamageModifier.RESISTANCE, 0); - // Base is now the final damage. Why u no have setFinalDamage? - e.setDamage(EntityDamageEvent.DamageModifier.BASE, newDamage); + if (cause!=DamageCause.DROWNING && cause!=DamageCause.STARVATION && cause!=DamageCause.SUFFOCATION && + cause!=DamageCause.SUICIDE && cause!=DamageCause.FLY_INTO_WALL && cause!=DamageCause.POISON) { - int durability = p.getInventory().getChestplate().getDurability(); + int durability = p.getInventory().getChestplate().getDurability(); int maxDurability = p.getInventory().getChestplate().getType().getMaxDurability(); - int newDurability = (int) (durability + ((int)(damage/4) > 1 ? (int)(damage/4) : 1)); + int newDurability = (int) (durability + ((int)(e.getDamage()/4) > 1 ? (int)(e.getDamage()/4) : 1)); // If the elytra has the durability enchantment. if (p.getInventory().getChestplate().containsEnchantment(Enchantment.DURABILITY)) { @@ -232,12 +300,16 @@ public class EventHandlers implements Listener { } } + + // Remove item from player's chestplate slot and puts it in their normal inventory. public void enquipChestPlayer(Player p) { p.getInventory().addItem(p.getInventory().getChestplate()); p.getInventory().getChestplate().setAmount(0); } + + // Check if the player is trying to equip a broken elytra (and prevent that). @EventHandler public void playerEquipsArmor(InventoryClickEvent e){