From f96a16457504daca31b9e5ee682f5c3d710ee5a8 Mon Sep 17 00:00:00 2001 From: YouHaveTrouble Date: Mon, 28 Oct 2024 17:07:07 +0100 Subject: [PATCH] add curse of panic --- .../youhavetrouble/enchantio/Enchantio.java | 3 + .../enchantio/EnchantioConfig.java | 53 +++++++-- .../enchantio/enchants/PanicEnchant.java | 106 ++++++++++++++++++ .../enchantio/events/PlayerPanicEvent.java | 68 +++++++++++ .../enchantio/listeners/PanicListener.java | 76 +++++++++++++ 5 files changed, 298 insertions(+), 8 deletions(-) create mode 100644 src/main/java/me/youhavetrouble/enchantio/enchants/PanicEnchant.java create mode 100644 src/main/java/me/youhavetrouble/enchantio/events/PlayerPanicEvent.java create mode 100644 src/main/java/me/youhavetrouble/enchantio/listeners/PanicListener.java diff --git a/src/main/java/me/youhavetrouble/enchantio/Enchantio.java b/src/main/java/me/youhavetrouble/enchantio/Enchantio.java index 0c66341..a2faa03 100644 --- a/src/main/java/me/youhavetrouble/enchantio/Enchantio.java +++ b/src/main/java/me/youhavetrouble/enchantio/Enchantio.java @@ -26,6 +26,9 @@ public final class Enchantio extends JavaPlugin { if (EnchantioConfig.ENCHANTS.containsKey(SmeltingEnchant.KEY)) { getServer().getPluginManager().registerEvents(new SmeltingListener(), this); } + if (EnchantioConfig.ENCHANTS.containsKey(PanicEnchant.KEY)) { + getServer().getPluginManager().registerEvents(new PanicListener(), this); + } } @Override diff --git a/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java b/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java index b112a8d..e5f9913 100644 --- a/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java +++ b/src/main/java/me/youhavetrouble/enchantio/EnchantioConfig.java @@ -79,15 +79,15 @@ public class EnchantioConfig { } TelepathyEnchant telepathyEnchant = new TelepathyEnchant( - getInt(telepathySection,"anvilCost", 1), - getInt(telepathySection,"weight", 5), + getInt(telepathySection, "anvilCost", 1), + getInt(telepathySection, "weight", 5), EnchantmentRegistryEntry.EnchantmentCost.of( - getInt(telepathySection,"minimumCost.base", 15), - getInt(telepathySection,"minimumCost.additionalPerLevel", 1) + getInt(telepathySection, "minimumCost.base", 15), + getInt(telepathySection, "minimumCost.additionalPerLevel", 1) ), EnchantmentRegistryEntry.EnchantmentCost.of( - getInt(telepathySection,"maximumCost.base", 65), - getInt(telepathySection,"maximumCost.additionalPerLevel", 1) + getInt(telepathySection, "maximumCost.base", 65), + getInt(telepathySection, "maximumCost.additionalPerLevel", 1) ), getBoolean(telepathySection, "canGetFromEnchantingTable", true), getTagsFromList(getStringList( @@ -147,7 +147,7 @@ public class EnchantioConfig { ), EnchantmentRegistryEntry.EnchantmentCost.of( getInt(executionerSection, "maximumCost.base", 65), - getInt(executionerSection,"maximumCost.additionalPerLevel", 1) + getInt(executionerSection, "maximumCost.additionalPerLevel", 1) ), getBoolean(executionerSection, "canGetFromEnchantingTable", true), getTagsFromList(getStringList( @@ -157,7 +157,7 @@ public class EnchantioConfig { "#minecraft:enchantable/weapon" ) )), - getInt(executionerSection,"maxLevel", 5), + getInt(executionerSection, "maxLevel", 5), getDouble(executionerSection, "damageMultiplierPerLevel", 0.05), getDouble(executionerSection, "maxDamageHpThreshold", 0.25) ); @@ -228,6 +228,43 @@ public class EnchantioConfig { ENCHANTS.put(SmeltingEnchant.KEY, smeltingEnchant); } + ConfigurationSection cursesSection = configuration.getConfigurationSection("curses"); + if (cursesSection == null) { + cursesSection = configuration.createSection("curses"); + } + + ConfigurationSection panicSection = cursesSection.getConfigurationSection("panic"); + if (panicSection == null) { + panicSection = cursesSection.createSection("panic"); + } + + PanicEnchant panicEnchant = new PanicEnchant( + getInt(panicSection, "anvilCost", 1), + getInt(panicSection, "weight", 2), + EnchantmentRegistryEntry.EnchantmentCost.of( + getInt(panicSection, "minimumCost.base", 0), + getInt(panicSection, "minimumCost.additionalPerLevel", 3) + ), + EnchantmentRegistryEntry.EnchantmentCost.of( + getInt(panicSection, "maximumCost.base", 20), + getInt(panicSection, "maximumCost.additionalPerLevel", 1) + ), + getBoolean(panicSection, "canGetFromEnchantingTable", true), + getTagsFromList(getStringList( + panicSection, + "supportedItemTags", + List.of( + "#minecraft:enchantable/armor" + ) + )), + getInt(panicSection, "maxLevel", 1), + getDouble(panicSection, "panicChancePerLevel", 0.025) + ); + + if (getBoolean(panicSection, "enabled", true)) { + ENCHANTS.put(PanicEnchant.KEY, panicEnchant); + } + configuration.save(configFile); } diff --git a/src/main/java/me/youhavetrouble/enchantio/enchants/PanicEnchant.java b/src/main/java/me/youhavetrouble/enchantio/enchants/PanicEnchant.java new file mode 100644 index 0000000..ac4ab30 --- /dev/null +++ b/src/main/java/me/youhavetrouble/enchantio/enchants/PanicEnchant.java @@ -0,0 +1,106 @@ +package me.youhavetrouble.enchantio.enchants; + +import io.papermc.paper.registry.data.EnchantmentRegistryEntry; +import io.papermc.paper.registry.keys.tags.EnchantmentTagKeys; +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.enchantments.Enchantment; +import org.bukkit.inventory.EquipmentSlotGroup; +import org.bukkit.inventory.ItemType; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@SuppressWarnings("UnstableApiUsage") +public class PanicEnchant implements EnchantioEnchant { + + public static final Key KEY = Key.key("enchantio:panic_curse"); + + private final int anvilCost, weight, maxLevel; + private final EnchantmentRegistryEntry.EnchantmentCost minimumCost; + private final EnchantmentRegistryEntry.EnchantmentCost maximumCost; + private final double panicChancePerLevel; + private final Set> supportedItemTags; + private final Set> enchantTagKeys = new HashSet<>(); + + public PanicEnchant( + int anvilCost, + int weight, + EnchantmentRegistryEntry.EnchantmentCost minimumCost, + EnchantmentRegistryEntry.EnchantmentCost maximumCost, + boolean canGetFromEnchantingTable, + Set> supportedItemTags, + int maxLevel, + double panicChancePerLevel + ) { + this.anvilCost = anvilCost; + this.weight = weight; + this.maxLevel = maxLevel; + this.minimumCost = minimumCost; + this.maximumCost = maximumCost; + this.supportedItemTags = supportedItemTags; + this.panicChancePerLevel = panicChancePerLevel; + if (canGetFromEnchantingTable) { + enchantTagKeys.add(EnchantmentTagKeys.IN_ENCHANTING_TABLE); + } + enchantTagKeys.add(EnchantmentTagKeys.CURSE); + } + + @Override + public Key getKey() { + return KEY; + } + + @Override + public Component getDescription() { + return Component.translatable("enchantio.enchant.panic_curse", "Curse of Panic"); + } + + @Override + public int getAnvilCost() { + return anvilCost; + } + + @Override + public int getMaxLevel() { + return maxLevel; + } + + @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.ARMOR); + } + + @Override + public Set> getSupportedItems() { + return supportedItemTags; + } + + @Override + public Set> getEnchantTagKeys() { + return Collections.unmodifiableSet(enchantTagKeys); + } + + public double getPanicChancePerLevel() { + return panicChancePerLevel; + } + +} diff --git a/src/main/java/me/youhavetrouble/enchantio/events/PlayerPanicEvent.java b/src/main/java/me/youhavetrouble/enchantio/events/PlayerPanicEvent.java new file mode 100644 index 0000000..3372f33 --- /dev/null +++ b/src/main/java/me/youhavetrouble/enchantio/events/PlayerPanicEvent.java @@ -0,0 +1,68 @@ +package me.youhavetrouble.enchantio.events; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Called when a player with the Panic enchantment takes damage and their hotbar is scrambled. + */ +public class PlayerPanicEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList HANDLERS = new HandlerList(); + + private boolean cancelled = false; + private final List scrambledItems; + + public PlayerPanicEvent(@NotNull Player player, @NotNull List scrambledItems) { + super(player); + this.scrambledItems = scrambledItems; + } + + /** + * Get the hotbar items that will be set for the player. List order will be preserved. + * @return The unmodifiable list of hotbar items + */ + public List getScrambledItems() { + return Collections.unmodifiableList(scrambledItems); + } + + /** + * Set the new player hotbar items. List order will be preserved. List must have a size of 9. + * @param scrambledItems The new hotbar items + */ + public void setScrambledItems(@NotNull List scrambledItems) { + if (scrambledItems.size() != 9) { + throw new IllegalArgumentException("Scrambled items must have a size of 9"); + } + this.scrambledItems.clear(); + this.scrambledItems.addAll(scrambledItems); + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLERS; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @NotNull + public static HandlerList getHandlerList() { + return HANDLERS; + } + +} diff --git a/src/main/java/me/youhavetrouble/enchantio/listeners/PanicListener.java b/src/main/java/me/youhavetrouble/enchantio/listeners/PanicListener.java new file mode 100644 index 0000000..304407e --- /dev/null +++ b/src/main/java/me/youhavetrouble/enchantio/listeners/PanicListener.java @@ -0,0 +1,76 @@ +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 me.youhavetrouble.enchantio.enchants.PanicEnchant; +import me.youhavetrouble.enchantio.events.PlayerPanicEvent; +import org.bukkit.Bukkit; +import org.bukkit.Registry; +import org.bukkit.enchantments.Enchantment; +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.EntityDamageEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.EquipmentSlotGroup; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public class PanicListener implements Listener { + + private final Registry registry = RegistryAccess.registryAccess().getRegistry(RegistryKey.ENCHANTMENT); + private final Enchantment panic = registry.get(PanicEnchant.KEY); + + @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) + public void onPlayerPanic(EntityDamageEvent event) { + if (panic == null) return; + + if (!(event.getEntity() instanceof Player player)) return; + + EnchantioEnchant enchant = EnchantioConfig.ENCHANTS.get(PanicEnchant.KEY); + if (!(enchant instanceof PanicEnchant panicEnchant)) return; + + PlayerInventory inventory = player.getInventory(); + ItemStack highestPanicEnchantItem = null; + + for (ItemStack item : inventory.getArmorContents()) { + if (item == null) continue; + if (item.containsEnchantment(panic)) { + if (highestPanicEnchantItem == null) { + highestPanicEnchantItem = item; + } else if (item.getEnchantmentLevel(panic) > highestPanicEnchantItem.getEnchantmentLevel(panic)) { + highestPanicEnchantItem = item; + } + } + } + + if (highestPanicEnchantItem == null) return; + + double chance = highestPanicEnchantItem.getEnchantmentLevel(panic) * panicEnchant.getPanicChancePerLevel(); + + if (ThreadLocalRandom.current().nextDouble() > chance) return; + + List hotbarItems = new ArrayList<>(Arrays.stream(inventory.getContents()).toList().subList(0, 9)); + Collections.shuffle(hotbarItems, ThreadLocalRandom.current()); + + PlayerPanicEvent playerPanicEvent = new PlayerPanicEvent(player, hotbarItems); + Bukkit.getPluginManager().callEvent(playerPanicEvent); + if (playerPanicEvent.isCancelled()) return; + + for (int i = 0; i < 9; i++) { + inventory.setItem(i, playerPanicEvent.getScrambledItems().get(i)); + } + + } + +}