add airbag enchant

This commit is contained in:
2024-10-29 20:08:10 +01:00
parent 16eae2bd58
commit 9f3960c649
5 changed files with 294 additions and 0 deletions
+6
View File
@@ -40,6 +40,12 @@ Adds a chance to drop the head of the entity killed (if entity has a head item a
**Description**:
Automatically smelts drops from mined blocks.
### Airbag
**Translation key**: `enchantio.enchantment.airbag`
**Description**:
Reduces damage from hitting a wall while flying with elytra.
## Curses
### Curse of Panic
@@ -2,8 +2,16 @@ package me.youhavetrouble.enchantio;
import me.youhavetrouble.enchantio.enchants.*;
import me.youhavetrouble.enchantio.listeners.*;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.EquipmentSlotGroup;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
@SuppressWarnings("UnstableApiUsage")
public final class Enchantio extends JavaPlugin {
@Override
@@ -26,6 +34,10 @@ public final class Enchantio extends JavaPlugin {
if (EnchantioConfig.ENCHANTS.containsKey(SmeltingEnchant.KEY)) {
getServer().getPluginManager().registerEvents(new SmeltingListener(), this);
}
if (EnchantioConfig.ENCHANTS.containsKey(AirbagEnchant.KEY)) {
getServer().getPluginManager().registerEvents(new AirbagListener(), this);
}
if (EnchantioConfig.ENCHANTS.containsKey(PanicEnchant.KEY)) {
getServer().getPluginManager().registerEvents(new PanicListener(), this);
}
@@ -37,4 +49,100 @@ public final class Enchantio extends JavaPlugin {
getLogger().severe("Enchantio is being disabled without a server shutdown. Server will be shut down to prevent issues.");
getServer().shutdown();
}
/**
* Returns highest enchantment level of the given enchantment on the given equipment.
* @param equipment The equipment to check for enchantments.
* @param enchantment The enchantment to check for.
* @return The highest level of the enchantment in the equipment.
*/
public static int getHighestEnchantLevel(
@NotNull EntityEquipment equipment,
@NotNull Enchantment enchantment
) {
int highestLevel = 0;
Set<EquipmentSlotGroup> equipmentSlotGroups = enchantment.getActiveSlotGroups();
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.ARMOR) || equipmentSlotGroups.contains(EquipmentSlotGroup.FEET)) {
ItemStack boots = equipment.getBoots();
if (boots != null) {
highestLevel = Math.max(highestLevel, boots.getEnchantmentLevel(enchantment));
}
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.ARMOR) || equipmentSlotGroups.contains(EquipmentSlotGroup.LEGS)) {
ItemStack leggings = equipment.getLeggings();
if (leggings != null) {
highestLevel = Math.max(highestLevel, leggings.getEnchantmentLevel(enchantment));
}
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.ARMOR) || equipmentSlotGroups.contains(EquipmentSlotGroup.CHEST)) {
ItemStack chestplate = equipment.getChestplate();
if (chestplate != null) {
highestLevel = Math.max(highestLevel, chestplate.getEnchantmentLevel(enchantment));
}
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.ARMOR) || equipmentSlotGroups.contains(EquipmentSlotGroup.HEAD)) {
ItemStack helmet = equipment.getHelmet();
if (helmet != null) {
highestLevel = Math.max(highestLevel, helmet.getEnchantmentLevel(enchantment));
}
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.HAND) || equipmentSlotGroups.contains(EquipmentSlotGroup.MAINHAND)) {
highestLevel = Math.max(highestLevel, equipment.getItemInMainHand().getEnchantmentLevel(enchantment));
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.HAND) || equipmentSlotGroups.contains(EquipmentSlotGroup.OFFHAND)) {
highestLevel = Math.max(highestLevel, equipment.getItemInOffHand().getEnchantmentLevel(enchantment));
}
return highestLevel;
}
/**
* Returns the sum of enchantment levels of the given enchantment on the given equipment.
* @param equipment The equipment to check for enchantments.
* @param enchantment The enchantment to check for.
* @return Sum of enchantment levels of the enchantment in the equipment.
*/
public static int getSumOfEnchantLevels(
@NotNull EntityEquipment equipment,
@NotNull Enchantment enchantment
) {
int level = 0;
Set<EquipmentSlotGroup> equipmentSlotGroups = enchantment.getActiveSlotGroups();
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.ARMOR) || equipmentSlotGroups.contains(EquipmentSlotGroup.FEET)) {
ItemStack boots = equipment.getBoots();
if (boots != null) {
level += boots.getEnchantmentLevel(enchantment);
}
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.ARMOR) || equipmentSlotGroups.contains(EquipmentSlotGroup.LEGS)) {
ItemStack leggings = equipment.getLeggings();
if (leggings != null) {
level += leggings.getEnchantmentLevel(enchantment);
}
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.ARMOR) || equipmentSlotGroups.contains(EquipmentSlotGroup.CHEST)) {
ItemStack chestplate = equipment.getChestplate();
if (chestplate != null) {
level += chestplate.getEnchantmentLevel(enchantment);
}
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.ARMOR) || equipmentSlotGroups.contains(EquipmentSlotGroup.HEAD)) {
ItemStack helmet = equipment.getHelmet();
if (helmet != null) {
level += helmet.getEnchantmentLevel(enchantment);
}
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.HAND) || equipmentSlotGroups.contains(EquipmentSlotGroup.MAINHAND)) {
ItemStack mainHand = equipment.getItemInMainHand();
level += mainHand.getEnchantmentLevel(enchantment);
}
if (equipmentSlotGroups.contains(EquipmentSlotGroup.ANY) || equipmentSlotGroups.contains(EquipmentSlotGroup.HAND) || equipmentSlotGroups.contains(EquipmentSlotGroup.OFFHAND)) {
ItemStack offHand = equipment.getItemInOffHand();
level += offHand.getEnchantmentLevel(enchantment);
}
return level;
}
}
@@ -1,5 +1,7 @@
package me.youhavetrouble.enchantio;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import io.papermc.paper.registry.data.EnchantmentRegistryEntry;
import io.papermc.paper.registry.keys.tags.ItemTypeTagKeys;
import io.papermc.paper.registry.tag.TagKey;
@@ -228,6 +230,38 @@ public class EnchantioConfig {
ENCHANTS.put(SmeltingEnchant.KEY, smeltingEnchant);
}
ConfigurationSection airbagSection = enchantsSection.getConfigurationSection("airbag");
if (airbagSection == null) {
airbagSection = enchantsSection.createSection("cushion");
}
AirbagEnchant airbagEnchant = new AirbagEnchant(
getInt(airbagSection, "anvilCost", 1),
getInt(airbagSection, "weight", 10),
EnchantmentRegistryEntry.EnchantmentCost.of(
getInt(airbagSection, "minimumCost.base", 40),
getInt(airbagSection, "minimumCost.additionalPerLevel", 3)
),
EnchantmentRegistryEntry.EnchantmentCost.of(
getInt(airbagSection, "maximumCost.base", 65),
getInt(airbagSection, "maximumCost.additionalPerLevel", 1)
),
getBoolean(airbagSection, "canGetFromEnchantingTable", true),
getTagsFromList(getStringList(
airbagSection,
"supportedItemTags",
List.of(
"minecraft:elytra"
)
)),
getInt(airbagSection, "maxLevel", 4),
getDouble(airbagSection, "damageReductionPerLevel", 0.2)
);
if (getBoolean(airbagSection, "enabled", true)) {
ENCHANTS.put(AirbagEnchant.KEY, airbagEnchant);
}
ConfigurationSection cursesSection = configuration.getConfigurationSection("curses");
if (cursesSection == null) {
cursesSection = configuration.createSection("curses");
@@ -0,0 +1,105 @@
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 AirbagEnchant implements EnchantioEnchant {
public static final Key KEY = Key.key("enchantio:airbag");
private final int anvilCost, weight, maxLevel;
private final EnchantmentRegistryEntry.EnchantmentCost minimumCost;
private final EnchantmentRegistryEntry.EnchantmentCost maximumCost;
private final Set<TagEntry<ItemType>> supportedItemTags;
private final Set<TagKey<Enchantment>> enchantTagKeys = new HashSet<>();
private final double damageReductionPerLevel;
public AirbagEnchant(
int anvilCost,
int weight,
EnchantmentRegistryEntry.EnchantmentCost minimumCost,
EnchantmentRegistryEntry.EnchantmentCost maximumCost,
boolean canGetFromEnchantingTable,
Set<TagEntry<ItemType>> supportedItemTags,
int maxLevel,
double damageReductionPerLevel
) {
this.anvilCost = anvilCost;
this.weight = weight;
this.maxLevel = maxLevel;
this.minimumCost = minimumCost;
this.maximumCost = maximumCost;
this.supportedItemTags = supportedItemTags;
this.damageReductionPerLevel = damageReductionPerLevel;
if (canGetFromEnchantingTable) {
enchantTagKeys.add(EnchantmentTagKeys.IN_ENCHANTING_TABLE);
}
}
@Override
public Key getKey() {
return KEY;
}
@Override
public Component getDescription() {
return Component.translatable("enchantio.enchant.airbag", "Airbag");
}
@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<EquipmentSlotGroup> getActiveSlots() {
return Set.of(EquipmentSlotGroup.ARMOR);
}
@Override
public Set<TagEntry<ItemType>> getSupportedItems() {
return supportedItemTags;
}
@Override
public Set<TagKey<Enchantment>> getEnchantTagKeys() {
return Collections.unmodifiableSet(enchantTagKeys);
}
public double getDamageReductionPerLevel() {
return damageReductionPerLevel;
}
}
@@ -0,0 +1,41 @@
package me.youhavetrouble.enchantio.listeners;
import io.papermc.paper.registry.RegistryAccess;
import io.papermc.paper.registry.RegistryKey;
import me.youhavetrouble.enchantio.Enchantio;
import me.youhavetrouble.enchantio.EnchantioConfig;
import me.youhavetrouble.enchantio.enchants.AirbagEnchant;
import org.bukkit.Registry;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.LivingEntity;
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.EntityEquipment;
public class AirbagListener implements Listener {
private final Registry<Enchantment> registry = RegistryAccess.registryAccess().getRegistry(RegistryKey.ENCHANTMENT);
private final Enchantment airbag = registry.get(AirbagEnchant.KEY);
@EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL)
public void onCushionedFall(EntityDamageEvent event) {
if (airbag == null) return;
if (!(event.getEntity() instanceof LivingEntity livingEntity)) return;
if (!event.getCause().equals(EntityDamageEvent.DamageCause.FLY_INTO_WALL)) return;
double damage = event.getDamage();
EntityEquipment entityEquipment = livingEntity.getEquipment();
if (entityEquipment == null) return;
int levels = Enchantio.getSumOfEnchantLevels(entityEquipment, airbag);
if (levels == 0) return;
AirbagEnchant airbagEnchant = (AirbagEnchant) EnchantioConfig.ENCHANTS.get(AirbagEnchant.KEY);
double percentageDamageReduction = Math.min(1, levels * airbagEnchant.getDamageReductionPerLevel());
event.setDamage(damage * (1 - percentageDamageReduction));
}
}