All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.nukkit.item.enchantment.Enchantment Maven / Gradle / Ivy

There is a newer version: 1.20.40-r1
Show newest version
package cn.nukkit.item.enchantment;

import cn.nukkit.api.*;
import cn.nukkit.entity.Entity;
import cn.nukkit.event.entity.EntityDamageEvent;
import cn.nukkit.item.Item;
import cn.nukkit.item.enchantment.bow.EnchantmentBowFlame;
import cn.nukkit.item.enchantment.bow.EnchantmentBowInfinity;
import cn.nukkit.item.enchantment.bow.EnchantmentBowKnockback;
import cn.nukkit.item.enchantment.bow.EnchantmentBowPower;
import cn.nukkit.item.enchantment.crossbow.EnchantmentCrossbowMultishot;
import cn.nukkit.item.enchantment.crossbow.EnchantmentCrossbowPiercing;
import cn.nukkit.item.enchantment.crossbow.EnchantmentCrossbowQuickCharge;
import cn.nukkit.item.enchantment.damage.EnchantmentDamageAll;
import cn.nukkit.item.enchantment.damage.EnchantmentDamageArthropods;
import cn.nukkit.item.enchantment.damage.EnchantmentDamageSmite;
import cn.nukkit.item.enchantment.loot.EnchantmentLootDigging;
import cn.nukkit.item.enchantment.loot.EnchantmentLootFishing;
import cn.nukkit.item.enchantment.loot.EnchantmentLootWeapon;
import cn.nukkit.item.enchantment.protection.*;
import cn.nukkit.item.enchantment.sideeffect.SideEffect;
import cn.nukkit.item.enchantment.trident.EnchantmentTridentChanneling;
import cn.nukkit.item.enchantment.trident.EnchantmentTridentImpaling;
import cn.nukkit.item.enchantment.trident.EnchantmentTridentLoyalty;
import cn.nukkit.item.enchantment.trident.EnchantmentTridentRiptide;
import cn.nukkit.math.NukkitMath;
import io.netty.util.internal.EmptyArrays;
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;

import javax.annotation.Nonnull;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * An enchantment that can be to applied to an item.
 * 
 * @author MagicDroidX (Nukkit Project)
 */
public abstract class Enchantment implements Cloneable {
    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public static final Enchantment[] EMPTY_ARRAY = new Enchantment[0];

    protected static Enchantment[] enchantments;
    @PowerNukkitXOnly
    @Since("1.6.0.0-PNX")
    protected static Map enchantmentName2IDMap = new Object2IntArrayMap<>();

    public static final int ID_PROTECTION_ALL = 0;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_PROTECTION_ALL = "protection";
    public static final int ID_PROTECTION_FIRE = 1;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_PROTECTION_FIRE = "fire_protection";
    public static final int ID_PROTECTION_FALL = 2;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_PROTECTION_FALL = "feather_falling";
    public static final int ID_PROTECTION_EXPLOSION = 3;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_PROTECTION_EXPLOSION = "blast_protection";
    public static final int ID_PROTECTION_PROJECTILE = 4;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_PROTECTION_PROJECTILE = "projectile_protection";
    public static final int ID_THORNS = 5;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_THORNS = "thorns";
    public static final int ID_WATER_BREATHING = 6;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_WATER_BREATHING = "respiration";
    public static final int ID_WATER_WALKER = 7;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_WATER_WALKER = "depth_strider";
    public static final int ID_WATER_WORKER = 8;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_WATER_WORKER = "aqua_affinity";
    public static final int ID_DAMAGE_ALL = 9;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_DAMAGE_ALL = "sharpness";
    public static final int ID_DAMAGE_SMITE = 10;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_DAMAGE_SMITE = "smite";
    public static final int ID_DAMAGE_ARTHROPODS = 11;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_DAMAGE_ARTHROPODS = "bane_of_arthropods";
    public static final int ID_KNOCKBACK = 12;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_KNOCKBACK = "knockback";
    public static final int ID_FIRE_ASPECT = 13;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_FIRE_ASPECT = "fire_aspect";
    public static final int ID_LOOTING = 14;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_LOOTING = "looting";
    public static final int ID_EFFICIENCY = 15;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_EFFICIENCY = "efficiency";
    public static final int ID_SILK_TOUCH = 16;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_SILK_TOUCH = "silk_touch";
    public static final int ID_DURABILITY = 17;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_DURABILITY = "unbreaking";
    public static final int ID_FORTUNE_DIGGING = 18;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_FORTUNE_DIGGING = "fortune";
    public static final int ID_BOW_POWER = 19;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_BOW_POWER = "power";
    public static final int ID_BOW_KNOCKBACK = 20;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_BOW_KNOCKBACK = "punch";
    public static final int ID_BOW_FLAME = 21;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_BOW_FLAME = "flame";
    public static final int ID_BOW_INFINITY = 22;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_BOW_INFINITY = "infinity";
    public static final int ID_FORTUNE_FISHING = 23;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_FORTUNE_FISHING = "luck_of_the_sea";
    public static final int ID_LURE = 24;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_LURE = "lure";
    public static final int ID_FROST_WALKER = 25;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_FROST_WALKER = "frost_walker";

    public static final int ID_MENDING = 26;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_MENDING = "mending";
    public static final int ID_BINDING_CURSE = 27;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_BINDING_CURSE = "binding";
    public static final int ID_VANISHING_CURSE = 28;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_VANISHING_CURSE = "vanishing";
    public static final int ID_TRIDENT_IMPALING = 29;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_TRIDENT_IMPALING = "impaling";
    public static final int ID_TRIDENT_RIPTIDE = 30;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_TRIDENT_RIPTIDE = "riptide";
    public static final int ID_TRIDENT_LOYALTY = 31;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_TRIDENT_LOYALTY = "loyalty";
    public static final int ID_TRIDENT_CHANNELING = 32;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_TRIDENT_CHANNELING = "channeling";
    @Since("1.4.0.0-PN") public static final int ID_CROSSBOW_MULTISHOT = 33;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_CROSSBOW_MULTISHOT = "multishot";
    @Since("1.4.0.0-PN") public static final int ID_CROSSBOW_PIERCING = 34;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_CROSSBOW_PIERCING = "piercing";
    @Since("1.4.0.0-PN") public static final int ID_CROSSBOW_QUICK_CHARGE = 35;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_CROSSBOW_QUICK_CHARGE = "quick_charge";
    @Since("1.4.0.0-PN") public static final int ID_SOUL_SPEED = 36;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_SOUL_SPEED = "soul_speed";
    @Since("1.4.0.0-PN") public static final int ID_SWIFT_SNEAK = 37;
    @PowerNukkitXOnly @Since("1.6.0.0-PNX") public static final String NAME_SWIFT_SNEAK = "swift_sneak";


    public static void init() {
        enchantments = new Enchantment[256];

        enchantments[ID_PROTECTION_ALL] = new EnchantmentProtectionAll();
        enchantments[ID_PROTECTION_FIRE] = new EnchantmentProtectionFire();
        enchantments[ID_PROTECTION_FALL] = new EnchantmentProtectionFall();
        enchantments[ID_PROTECTION_EXPLOSION] = new EnchantmentProtectionExplosion();
        enchantments[ID_PROTECTION_PROJECTILE] = new EnchantmentProtectionProjectile();
        enchantments[ID_THORNS] = new EnchantmentThorns();
        enchantments[ID_WATER_BREATHING] = new EnchantmentWaterBreath();
        enchantments[ID_WATER_WORKER] = new EnchantmentWaterWorker();
        enchantments[ID_WATER_WALKER] = new EnchantmentWaterWalker();
        enchantments[ID_DAMAGE_ALL] = new EnchantmentDamageAll();
        enchantments[ID_DAMAGE_SMITE] = new EnchantmentDamageSmite();
        enchantments[ID_DAMAGE_ARTHROPODS] = new EnchantmentDamageArthropods();
        enchantments[ID_KNOCKBACK] = new EnchantmentKnockback();
        enchantments[ID_FIRE_ASPECT] = new EnchantmentFireAspect();
        enchantments[ID_LOOTING] = new EnchantmentLootWeapon();
        enchantments[ID_EFFICIENCY] = new EnchantmentEfficiency();
        enchantments[ID_SILK_TOUCH] = new EnchantmentSilkTouch();
        enchantments[ID_DURABILITY] = new EnchantmentDurability();
        enchantments[ID_FORTUNE_DIGGING] = new EnchantmentLootDigging();
        enchantments[ID_BOW_POWER] = new EnchantmentBowPower();
        enchantments[ID_BOW_KNOCKBACK] = new EnchantmentBowKnockback();
        enchantments[ID_BOW_FLAME] = new EnchantmentBowFlame();
        enchantments[ID_BOW_INFINITY] = new EnchantmentBowInfinity();
        enchantments[ID_FORTUNE_FISHING] = new EnchantmentLootFishing();
        enchantments[ID_LURE] = new EnchantmentLure();
        enchantments[ID_FROST_WALKER] = new EnchantmentFrostWalker();
        enchantments[ID_MENDING]  = new EnchantmentMending();
        enchantments[ID_BINDING_CURSE]  = new EnchantmentBindingCurse();
        enchantments[ID_VANISHING_CURSE]  = new EnchantmentVanishingCurse();
        enchantments[ID_TRIDENT_IMPALING]  = new EnchantmentTridentImpaling();
        enchantments[ID_TRIDENT_RIPTIDE]  = new EnchantmentTridentRiptide();
        enchantments[ID_TRIDENT_LOYALTY]  = new EnchantmentTridentLoyalty();
        enchantments[ID_TRIDENT_CHANNELING]  = new EnchantmentTridentChanneling();
        enchantments[ID_CROSSBOW_MULTISHOT]  = new EnchantmentCrossbowMultishot();
        enchantments[ID_CROSSBOW_PIERCING]  = new EnchantmentCrossbowPiercing();
        enchantments[ID_CROSSBOW_QUICK_CHARGE]  = new EnchantmentCrossbowQuickCharge();
        enchantments[ID_SOUL_SPEED]  = new EnchantmentSoulSpeed();
        enchantments[ID_SWIFT_SNEAK] = new EnchantmentSwiftSneak();


        enchantmentName2IDMap.put(NAME_PROTECTION_ALL, ID_PROTECTION_ALL);
        enchantmentName2IDMap.put(NAME_PROTECTION_FIRE, ID_PROTECTION_FIRE);
        enchantmentName2IDMap.put(NAME_PROTECTION_FALL, ID_PROTECTION_FALL);
        enchantmentName2IDMap.put(NAME_PROTECTION_EXPLOSION, ID_PROTECTION_EXPLOSION);
        enchantmentName2IDMap.put(NAME_PROTECTION_PROJECTILE, ID_PROTECTION_PROJECTILE);
        enchantmentName2IDMap.put(NAME_THORNS, ID_THORNS);
        enchantmentName2IDMap.put(NAME_WATER_BREATHING, ID_WATER_BREATHING);
        enchantmentName2IDMap.put(NAME_WATER_WORKER, ID_WATER_WORKER);
        enchantmentName2IDMap.put(NAME_WATER_WALKER, ID_WATER_WALKER);
        enchantmentName2IDMap.put(NAME_DAMAGE_ALL, ID_DAMAGE_ALL);
        enchantmentName2IDMap.put(NAME_DAMAGE_SMITE, ID_DAMAGE_SMITE);
        enchantmentName2IDMap.put(NAME_DAMAGE_ARTHROPODS, ID_DAMAGE_ARTHROPODS);
        enchantmentName2IDMap.put(NAME_KNOCKBACK, ID_KNOCKBACK);
        enchantmentName2IDMap.put(NAME_FIRE_ASPECT, ID_FIRE_ASPECT);
        enchantmentName2IDMap.put(NAME_LOOTING, ID_LOOTING);
        enchantmentName2IDMap.put(NAME_EFFICIENCY, ID_EFFICIENCY);
        enchantmentName2IDMap.put(NAME_SILK_TOUCH, ID_SILK_TOUCH);
        enchantmentName2IDMap.put(NAME_DURABILITY, ID_DURABILITY);
        enchantmentName2IDMap.put(NAME_FORTUNE_DIGGING, ID_FORTUNE_DIGGING);
        enchantmentName2IDMap.put(NAME_BOW_POWER, ID_BOW_POWER);
        enchantmentName2IDMap.put(NAME_BOW_KNOCKBACK, ID_BOW_KNOCKBACK);
        enchantmentName2IDMap.put(NAME_BOW_FLAME, ID_BOW_FLAME);
        enchantmentName2IDMap.put(NAME_BOW_INFINITY, ID_BOW_INFINITY);
        enchantmentName2IDMap.put(NAME_FORTUNE_FISHING, ID_FORTUNE_FISHING);
        enchantmentName2IDMap.put(NAME_LURE, ID_LURE);
        enchantmentName2IDMap.put(NAME_FROST_WALKER, ID_FROST_WALKER);
        enchantmentName2IDMap.put(NAME_MENDING, ID_MENDING);
        enchantmentName2IDMap.put(NAME_BINDING_CURSE, ID_BINDING_CURSE);
        enchantmentName2IDMap.put(NAME_VANISHING_CURSE, ID_VANISHING_CURSE);
        enchantmentName2IDMap.put(NAME_TRIDENT_IMPALING, ID_TRIDENT_IMPALING);
        enchantmentName2IDMap.put(NAME_TRIDENT_RIPTIDE, ID_TRIDENT_RIPTIDE);
        enchantmentName2IDMap.put(NAME_TRIDENT_LOYALTY, ID_TRIDENT_LOYALTY);
        enchantmentName2IDMap.put(NAME_TRIDENT_CHANNELING, ID_TRIDENT_CHANNELING);
        enchantmentName2IDMap.put(NAME_CROSSBOW_MULTISHOT, ID_CROSSBOW_MULTISHOT);
        enchantmentName2IDMap.put(NAME_CROSSBOW_PIERCING, ID_CROSSBOW_PIERCING);
        enchantmentName2IDMap.put(NAME_CROSSBOW_QUICK_CHARGE, ID_CROSSBOW_QUICK_CHARGE);
        enchantmentName2IDMap.put(NAME_SOUL_SPEED, ID_SOUL_SPEED);
        enchantmentName2IDMap.put(NAME_SWIFT_SNEAK, ID_SWIFT_SNEAK);
    }

    /**
     * Returns the enchantment object registered with this ID, any change to the returned object affects 
     * the creation of new enchantments as the returned object is not a copy.
     * @param id The enchantment id.
     * @return The enchantment, if no enchantment is found with that id, {@link UnknownEnchantment} is returned.
     * The UnknownEnchantment will be always a new instance and changes to it does not affects other calls.
     */
    @Deprecated
    @DeprecationDetails(by = "PowerNukkit", reason = "This is very insecure and can break the environment", since = "1.4.0.0-PN",
            replaceWith = "getEnchantment(int)")
    public static Enchantment get(int id) {
        Enchantment enchantment = null;
        if (id >= 0 && id < enchantments.length) {
            enchantment = enchantments[id];
        }
        if (enchantment == null) {
            return new UnknownEnchantment(id);
        }
        return enchantment;
    }

    /**
     * The same as {@link #get(int)} but returns a safe copy of the enchantment.
     * @param id The enchantment id
     * @return A new enchantment object.
     */
    public static Enchantment getEnchantment(int id) {
        return get(id).clone();
    }

    @PowerNukkitXOnly
    @Since("1.6.0.0-PNX")
    public static Enchantment getEnchantment(String name) {
        return getEnchantment(enchantmentName2IDMap.get(name));
    }

    /**
     * Gets an array of all registered enchantments, the objects in the array are linked to the registry,
     * it's not safe to change them. Changing them can cause the same issue as documented in {@link #get(int)}
     * @return An array with the enchantment objects, the array may contain null objects but is very unlikely.
     */
    @Deprecated
    @DeprecationDetails(since = "1.4.0.0-PN", by = "PowerNukkit", 
            reason = "The objects returned by this method are not safe to use and the implementation may skip some enchantments",
            replaceWith = "getRegisteredEnchantments()"
    )
    public static Enchantment[] getEnchantments() {
        ArrayList list = new ArrayList<>();
        for (Enchantment enchantment : enchantments) {
            if (enchantment == null) {
                break;
            }

            list.add(enchantment);
        }

        return list.toArray(Enchantment.EMPTY_ARRAY);
    }

    /**
     * Gets a collection with a safe copy of all enchantments that are currently registered.
     * @return The objects can be modified without affecting the registry and the collection will not have null values.
     */
    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public static Collection getRegisteredEnchantments() {
        return Arrays.stream(enchantments)
                .filter(Objects::nonNull)
                .map(Enchantment::clone)
                .collect(Collectors.toList());
    }

    @PowerNukkitXOnly
    @Since("1.6.0.0-PNX")
    public static Map getEnchantmentName2IDMap() {
        return enchantmentName2IDMap;
    }

    /**
     * The internal ID which this enchantment got registered.
     */
    public final int id;
    private final Rarity rarity;

    /**
     * The group of objects that this enchantment can be applied.
     */
    @Nonnull
    public EnchantmentType type;

    /**
     * The level of this enchantment. Starting from {@code 1}.
     */
    protected int level = 1;

    /**
     * The name visible by the player, this is used in conjunction with {@link #getName()}, 
     * unless modified with an override, the getter will automatically add 
     * "%enchantment." as prefix to grab the translation key 
     */
    protected final String name;

    /**
     * Constructs this instance using the given data and with level 1.
     * @param id The enchantment ID
     * @param name The translation key without the "%enchantment." suffix
     * @param weight How rare this enchantment is, from {@code 1} to {@code 10} both inclusive where {@code 1} is the rarest
     * @param type Where the enchantment can be applied
     */
    @PowerNukkitOnly("Was removed from Nukkit in 1.4.0.0-PN, keeping it in PowerNukkit for backward compatibility")
    @Deprecated @DeprecationDetails(by = "Cloudburst Nukkit", since = "1.4.0.0-PN", reason = "Changed the signature without backward compatibility",
            replaceWith = "Enchantment(int, String, Rarity, EnchantmentType)")
    protected Enchantment(int id, String name, int weight, EnchantmentType type) {
        this(id, name, Rarity.fromWeight(weight), type);
    }

    /**
     * Constructs this instance using the given data and with level 1.
     * @param id The enchantment ID
     * @param name The translation key without the "%enchantment." suffix
     * @param rarity How rare this enchantment is
     * @param type Where the enchantment can be applied
     */
    @Since("1.4.0.0-PN")
    protected Enchantment(int id, String name, Rarity rarity, EnchantmentType type) {
        this.id = id;
        this.rarity = rarity;
        this.type = type;

        this.name = name;
    }

    /**
     * The current level of this enchantment. {@code 0} means that the enchantment is not applied.
     * @return The level starting from {@code 1}.
     */
    public int getLevel() {
        return level;
    }

    /**
     * Changes the level of this enchantment.
     * The level is clamped between the values returned in {@link #getMinLevel()} and {@link #getMaxLevel()}.
     * 
     * @param level The level starting from {@code 1}.
     * @return This object so you can do chained calls
     */

    @Nonnull
    public Enchantment setLevel(int level) {
        return this.setLevel(level, true);
    }

    /**
     * Changes the level of this enchantment.
     * When the {@code safe} param is {@code true}, the level is clamped between the values 
     * returned in {@link #getMinLevel()} and {@link #getMaxLevel()}.
     *
     * @param level The level starting from {@code 1}.
     * @param safe If the level should clamped or applied directly
     * @return This object so you can do chained calls
     */
    @Nonnull
    public Enchantment setLevel(int level, boolean safe) {
        if (!safe) {
            this.level = level;
            return this;
        }

        this.level = NukkitMath.clamp(level, this.getMinLevel(), this.getMaxLevel());

        return this;
    }

    /**
     * The ID of this enchantment. 
     */
    public int getId() {
        return id;
    }

    /**
     * How rare this enchantment is.
     */
    @Since("1.4.0.0-PN")
    @Nonnull
    public Rarity getRarity() {
        return this.rarity;
    }

    /**
     * How rare this enchantment is, from {@code 1} to {@code 10} where {@code 1} is the rarest.
     * @deprecated use {@link Rarity#getWeight()} instead
     */
    @DeprecationDetails(since = "1.4.0.0-PN", by = "Cloudburst Nukkit", 
            reason = "Refactored enchantments and now uses a Rarity enum", 
            replaceWith = "getRarity().getWeight()")
    @Deprecated
    public int getWeight() {
        return this.rarity.getWeight();
    }

    /**
     * The minimum safe level which is possible with this enchantment. It is usually {@code 1}.
     */
    public int getMinLevel() {
        return 1;
    }

    /**
     * The maximum safe level which is possible with this enchantment.
     */
    public int getMaxLevel() {
        return 1;
    }

    /**
     * The maximum level that can be obtained using an enchanting table.
     */
    public int getMaxEnchantableLevel() {
        return getMaxLevel();
    }

    /**
     * The minimum enchantability for the given level as described in https://minecraft.gamepedia.com/Enchanting/Levels
     * @param level The level being checked
     * @return The minimum value
     */
    public int getMinEnchantAbility(int level) {
        return 1 + level * 10;
    }

    /**
     * The maximum enchantability for the given level as described in https://minecraft.gamepedia.com/Enchanting/Levels
     * @param level The level being checked
     * @return The maximum value
     */
    public int getMaxEnchantAbility(int level) {
        return this.getMinEnchantAbility(level) + 5;
    }

    public float getProtectionFactor(EntityDamageEvent event) {
        return 0;
    }

    public double getDamageBonus(Entity entity) {
        return 0;
    }

    public void doPostAttack(Entity attacker, Entity entity) {

    }

    @Since("FUTURE")
    public void doAttack(Entity attacker, Entity entity) {

    }

    public void doPostHurt(Entity attacker, Entity entity) {

    }

    /**
     * Returns true if and only if this enchantment is compatible with the other and 
     * the other is also compatible with this enchantment. 
     * @param enchantment The enchantment which is being checked
     * @return If both enchantments are compatible
     * @implNote Cloudburst Nukkit added the final modifier, PowerNukkit removed it to maintain backward compatibility.
     * The right way to implement compatibility now is to override {@link #checkCompatibility(Enchantment)}
     *  and also make sure to keep it protected! Some overrides was incorrectly made public, let's avoid this mistake
     */
    @PowerNukkitDifference(since = "1.4.0.0-PN", 
            info = "Cloudburst Nukkit added the final modifier, we removed it to maintain backward compatibility. " +
                    "The right way to implement compatibility now is to override checkCompatibility(Enchantment enchantment) " +
                    "and also make sure to keep it protected! Some overrides was incorrectly made public, let's avoid this mistake."
    )
    public boolean isCompatibleWith(@Nonnull Enchantment enchantment) {
        return this.checkCompatibility(enchantment) && enchantment.checkCompatibility(this);
    }

    /**
     * Checks if this enchantment can be applied to an item that have the give enchantment without doing reverse check.
     * @param enchantment The enchantment to be checked
     * @return If this enchantment is compatible with the other enchantment.
     */
    @Since("1.4.0.0-PN")
    protected boolean checkCompatibility(Enchantment enchantment) {
        return this != enchantment;
    }

    //return the translation key for the enchantment
    public String getName() {
        return "%enchantment." + this.name;
    }

    @PowerNukkitXOnly
    @Since("1.6.0.0-PNX")
    public String getOriginalName(){
        return this.name;
    }

    /**
     * Checks if the given item have a type which is compatible with this enchantment. This method does not check
     * if the item already have incompatible enchantments.
     * @param item The item to be checked
     * @return If the type of the item is valid for this enchantment
     */
    public boolean canEnchant(@Nonnull Item item) {
        return this.type.canEnchantItem(item);
    }

    public boolean isMajor() {
        return false;
    }

    @PowerNukkitOnly
    @Since("1.5.1.0-PN")
    @Nonnull
    public SideEffect[] getAttackSideEffects(@Nonnull Entity attacker, @Nonnull Entity entity) {
        return SideEffect.EMPTY_ARRAY;
    }

    @Override
    protected Enchantment clone() {
        try {
            return (Enchantment) super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }

    /**
     * Checks if an item can have this enchantment. It's not strict to the enchantment table.
     */
    @PowerNukkitOnly @Since("1.2.1.0-PN")
    @Deprecated @DeprecationDetails(by = "PowerNukkit", since = "1.4.0.0-PN", 
            reason = "Does the same as canEnchant(item)", replaceWith = "canEnchant(item)")
    public boolean isItemAcceptable(Item item) {
        return canEnchant(item);
    }

    public static final String[] words = {"the", "elder", "scrolls", "klaatu", "berata", "niktu", "xyzzy", "bless", "curse", "light", "darkness", "fire", "air", "earth", "water", "hot", "dry", "cold", "wet", "ignite", "snuff", "embiggen", "twist", "shorten", "stretch", "fiddle", "destroy", "imbue", "galvanize", "enchant", "free", "limited", "range", "of", "towards", "inside", "sphere", "cube", "self", "other", "ball", "mental", "physical", "grow", "shrink", "demon", "elemental", "spirit", "animal", "creature", "beast", "humanoid", "undead", "fresh", "stale"};

    public static String getRandomName() {
        int count = ThreadLocalRandom.current().nextInt(3, 6);
        HashSet set = new LinkedHashSet<>();
        while (set.size() < count) {
            set.add(Enchantment.words[ThreadLocalRandom.current().nextInt(0, Enchantment.words.length)]);
        }

        String[] words = set.toArray(EmptyArrays.EMPTY_STRINGS);
        return String.join(" ", words);
    }

    private static class UnknownEnchantment extends Enchantment {

        protected UnknownEnchantment(int id) {
            super(id, "unknown", Rarity.VERY_RARE, EnchantmentType.ALL);
        }
    }

    /**
     * How rare an enchantment is.
     */
    @Since("1.4.0.0-PN")
    public enum Rarity {
        @Since("1.4.0.0-PN") COMMON(10),
        @Since("1.4.0.0-PN") UNCOMMON(5),
        @Since("1.4.0.0-PN") RARE(2),
        @Since("1.4.0.0-PN") VERY_RARE(1);

        private final int weight;

        Rarity(int weight) {
            this.weight = weight;
        }

        @Since("1.4.0.0-PN")
        public int getWeight() {
            return this.weight;
        }

        /**
         * Converts the weight to the closest rarity using floor semantic.
         * @param weight The enchantment weight
         * @return The closest rarity
         */
        @Since("1.4.0.0-PN")
        public static Rarity fromWeight(int weight) {
            if (weight < 2) {
                return VERY_RARE;
            } else if (weight < 5) {
                return RARE;
            } else if (weight < 10) {
                return UNCOMMON;
            }
            return COMMON;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy