From 776359f35556a877325f25502978aaf88c78e0ab Mon Sep 17 00:00:00 2001 From: YouHaveTrouble Date: Sat, 26 Oct 2024 11:30:03 +0200 Subject: [PATCH] add beheading enchant --- .../youhavetrouble/enchantio/Enchantio.java | 13 +-- .../enchantio/EnchantioConfig.java | 32 ++++++ .../enchantio/enchants/BeheadingEnchant.java | 105 ++++++++++++++++++ .../listeners/BeheadingListener.java | 101 +++++++++++++++++ 4 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 src/main/java/me/youhavetrouble/enchantio/enchants/BeheadingEnchant.java create mode 100644 src/main/java/me/youhavetrouble/enchantio/listeners/BeheadingListener.java diff --git a/src/main/java/me/youhavetrouble/enchantio/Enchantio.java b/src/main/java/me/youhavetrouble/enchantio/Enchantio.java index 9de708a..5a4ecac 100644 --- a/src/main/java/me/youhavetrouble/enchantio/Enchantio.java +++ b/src/main/java/me/youhavetrouble/enchantio/Enchantio.java @@ -1,13 +1,7 @@ package me.youhavetrouble.enchantio; -import me.youhavetrouble.enchantio.enchants.ExecutionerEnchant; -import me.youhavetrouble.enchantio.enchants.ReplantingEnchant; -import me.youhavetrouble.enchantio.enchants.SoulboundEnchant; -import me.youhavetrouble.enchantio.enchants.TelepathyEnchant; -import me.youhavetrouble.enchantio.listeners.ExecutionerListener; -import me.youhavetrouble.enchantio.listeners.ReplantingListener; -import me.youhavetrouble.enchantio.listeners.SoulboundListener; -import me.youhavetrouble.enchantio.listeners.TelepathyListener; +import me.youhavetrouble.enchantio.enchants.*; +import me.youhavetrouble.enchantio.listeners.*; import org.bukkit.plugin.java.JavaPlugin; public final class Enchantio extends JavaPlugin { @@ -26,6 +20,9 @@ public final class Enchantio extends JavaPlugin { if (EnchantioConfig.ENCHANTS.containsKey(ExecutionerEnchant.KEY)) { getServer().getPluginManager().registerEvents(new ExecutionerListener(), this); } + if (EnchantioConfig.ENCHANTS.containsKey(BeheadingEnchant.KEY)) { + getServer().getPluginManager().registerEvents(new BeheadingListener(), this); + } } @Override diff --git a/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java b/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java index 3f33e61..200dc57 100644 --- a/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java +++ b/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java @@ -166,6 +166,38 @@ public class EnchantioConfig { ENCHANTS.put(ExecutionerEnchant.KEY, executionerEnchant); } + ConfigurationSection beheadingSection = enchantsSection.getConfigurationSection("beheading"); + if (beheadingSection == null) { + beheadingSection = enchantsSection.createSection("beheading"); + } + + BeheadingEnchant beheadingEnchant = new BeheadingEnchant( + getInt(beheadingSection, "anvilCost", 1), + getInt(beheadingSection, "weight", 10), + EnchantmentRegistryEntry.EnchantmentCost.of( + getInt(beheadingSection, "minimumCost.base", 40), + getInt(beheadingSection, "minimumCost.additionalPerLevel", 3) + ), + EnchantmentRegistryEntry.EnchantmentCost.of( + getInt(beheadingSection, "maximumCost.base", 65), + getInt(beheadingSection, "maximumCost.additionalPerLevel", 1) + ), + getBoolean(beheadingSection, "canGetFromEnchantingTable", true), + getTagsFromList(getStringList( + beheadingSection, + "supportedItemTags", + List.of( + "#minecraft:axes" + ) + )), + getInt(beheadingSection, "maxLevel", 5), + getDouble(beheadingSection, "chanceToDropHeadPerLevel", 0.02) + ); + + if (getBoolean(beheadingSection, "enabled", true)) { + ENCHANTS.put(BeheadingEnchant.KEY, beheadingEnchant); + } + configuration.save(configFile); } diff --git a/src/main/java/me/youhavetrouble/enchantio/enchants/BeheadingEnchant.java b/src/main/java/me/youhavetrouble/enchantio/enchants/BeheadingEnchant.java new file mode 100644 index 0000000..7575c04 --- /dev/null +++ b/src/main/java/me/youhavetrouble/enchantio/enchants/BeheadingEnchant.java @@ -0,0 +1,105 @@ +package me.youhavetrouble.enchantio.enchants; + +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.data.EnchantmentRegistryEntry; +import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.tag.TagEntry; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import org.bukkit.inventory.EquipmentSlotGroup; +import org.bukkit.inventory.ItemType; + +import java.util.Set; + +@SuppressWarnings("UnstableApiUsage") +public class BeheadingEnchant implements EnchantioEnchant { + + public static final Key KEY = Key.key("enchantio:beheading"); + + private final int anvilCost, weight, maxLevel; + private final EnchantmentRegistryEntry.EnchantmentCost minimumCost; + private final EnchantmentRegistryEntry.EnchantmentCost maximumCost; + private final boolean canGetFromEnchantingTable; + private final Set> supportedItemTags; + private final double chanceToDropHeadPerLevel; + + public BeheadingEnchant( + int anvilCost, + int weight, + EnchantmentRegistryEntry.EnchantmentCost minimumCost, + EnchantmentRegistryEntry.EnchantmentCost maximumCost, + boolean canGetFromEnchantingTable, + Set> supportedItemTags, + int maxLevel, + double chanceToDropHeadPerLevel + ) { + this.anvilCost = anvilCost; + this.weight = weight; + this.minimumCost = minimumCost; + this.maximumCost = maximumCost; + this.canGetFromEnchantingTable = canGetFromEnchantingTable; + this.supportedItemTags = supportedItemTags; + this.maxLevel = maxLevel; + this.chanceToDropHeadPerLevel = chanceToDropHeadPerLevel; + } + + @Override + public Key getKey() { + return KEY; + } + + @Override + public Component getDescription() { + return Component.translatable("enchantio.enchant.beheading", "Beheading"); + } + + @Override + public int getAnvilCost() { + return anvilCost; + } + + @Override + public int getMaxLevel() { + return maxLevel; + } + + public double getChanceToDropHeadPerLevel() { + return chanceToDropHeadPerLevel; + } + + @Override + public int getWeight() { + return weight; + } + + @Override + public EnchantmentRegistryEntry.EnchantmentCost getMinimumCost() { + return minimumCost; + } + + @Override + public EnchantmentRegistryEntry.EnchantmentCost getMaximumCost() { + return maximumCost; + } + + @Override + public Iterable getActiveSlots() { + return Set.of(EquipmentSlotGroup.ANY); + } + + @Override + public boolean canGetFromEnchantingTable() { + return canGetFromEnchantingTable; + } + + @Override + public TagKey getTagForSupportedItems() { + return TagKey.create(RegistryKey.ITEM, Key.key("enchantio:beheading_enchantable")); + } + + @Override + public Set> getSupportedItems() { + return supportedItemTags; + } + +} diff --git a/src/main/java/me/youhavetrouble/enchantio/listeners/BeheadingListener.java b/src/main/java/me/youhavetrouble/enchantio/listeners/BeheadingListener.java new file mode 100644 index 0000000..ac34b87 --- /dev/null +++ b/src/main/java/me/youhavetrouble/enchantio/listeners/BeheadingListener.java @@ -0,0 +1,101 @@ +package me.youhavetrouble.enchantio.listeners; + +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import me.youhavetrouble.enchantio.EnchantioConfig; +import me.youhavetrouble.enchantio.enchants.BeheadingEnchant; +import me.youhavetrouble.enchantio.enchants.EnchantioEnchant; +import org.bukkit.Material; +import org.bukkit.Registry; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ThreadLocalRandom; + + +@SuppressWarnings("UnstableApiUsage") +public class BeheadingListener implements Listener { + + private final Registry registry = RegistryAccess.registryAccess().getRegistry(RegistryKey.ENCHANTMENT); + private final Enchantment beheading = registry.get(BeheadingEnchant.KEY); + + @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) + public void onBeheading(EntityDeathEvent event) { + if (beheading == null) return; + EnchantioEnchant enchant = EnchantioConfig.ENCHANTS.get(BeheadingEnchant.KEY); + if (!(enchant instanceof BeheadingEnchant beheadingEnchant)) return; + if (event.getEntity().getKiller() == null) return; + if (event.getDamageSource().isIndirect()) return; + Entity killer = event.getDamageSource().getCausingEntity(); + if (killer == null) return; + if (!(killer instanceof InventoryHolder inventoryHolder)) return; + if (!(inventoryHolder.getInventory() instanceof EntityEquipment entityEquipment)) return; + + ItemStack weapon = entityEquipment.getItemInMainHand(); + + if (!weapon.containsEnchantment(beheading)) return; + + double chance = weapon.getEnchantmentLevel(beheading) * beheadingEnchant.getChanceToDropHeadPerLevel(); + + if (ThreadLocalRandom.current().nextDouble() > chance) return; + + switch (event.getEntity().getType()) { + case ZOMBIE -> { + if (listContainsItemType(event.getDrops(), Material.ZOMBIE_HEAD)) return; + event.getDrops().add(new ItemStack(org.bukkit.Material.ZOMBIE_HEAD)); + } + case PIGLIN -> { + if (listContainsItemType(event.getDrops(), Material.PIGLIN_HEAD)) return; + event.getDrops().add(new ItemStack(org.bukkit.Material.PIGLIN_HEAD)); + } + case WITHER_SKELETON -> { + if (listContainsItemType(event.getDrops(), Material.WITHER_SKELETON_SKULL)) return; + event.getDrops().add(new ItemStack(org.bukkit.Material.WITHER_SKELETON_SKULL)); + } + case SKELETON -> { + if (listContainsItemType(event.getDrops(), Material.SKELETON_SKULL)) return; + event.getDrops().add(new ItemStack(org.bukkit.Material.SKELETON_SKULL)); + } + case CREEPER -> { + if (listContainsItemType(event.getDrops(), Material.CREEPER_HEAD)) return; + event.getDrops().add(new ItemStack(org.bukkit.Material.CREEPER_HEAD)); + } + case ENDER_DRAGON -> { + if (listContainsItemType(event.getDrops(), Material.DRAGON_HEAD)) return; + event.getDrops().add(new ItemStack(org.bukkit.Material.DRAGON_HEAD)); + } + case PLAYER -> { + if (listContainsItemType(event.getDrops(), Material.PLAYER_HEAD)) return; + Player player = (Player) event.getEntity(); + event.getDrops().add(getPlayerHead(player)); + } + } + + } + + private boolean listContainsItemType(@NotNull Iterable list, @NotNull Material type) { + for (ItemStack item : list) { + if (type.equals(item.getType())) return true; + } + return false; + } + + private ItemStack getPlayerHead(@NotNull Player player) { + ItemStack head = new ItemStack(org.bukkit.Material.PLAYER_HEAD); + SkullMeta meta = (SkullMeta) head.getItemMeta(); + meta.setOwningPlayer(player); + head.setItemMeta(meta); + return head; + } + +}