v4.0.0 beta

This commit is contained in:
BuildTools 2024-03-24 17:11:31 +05:00
parent 1d508bb581
commit 13a40b39fc
210 changed files with 8200 additions and 7988 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>3.6.5</version>
<version>4.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -0,0 +1,7 @@
package su.nightexpress.excellentenchants.api;
public enum DistributionMode {
VANILLA,
CUSTOM
}

View File

@ -1,18 +1,18 @@
package su.nightexpress.excellentenchants.api.enchantment;
package su.nightexpress.excellentenchants.api;
import org.jetbrains.annotations.NotNull;
public enum ObtainType {
public enum DistributionWay {
ENCHANTING("Enchanting_Table"),
VILLAGER("Villagers"),
LOOT_GENERATION("Loot_Generation"),
FISHING("Fishing"),
MOB_SPAWNING("Mob_Spawning");
MOB_EQUIPMENT("Mob_Equipment");
private final String pathName;
ObtainType(@NotNull String pathName) {
DistributionWay(@NotNull String pathName) {
this.pathName = pathName;
}

View File

@ -0,0 +1,148 @@
package su.nightexpress.excellentenchants.api;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.StringUtil;
public class Modifier {
private double base;
private double perLevel;
private double step;
private double cap;
private ModifierAction action;
public Modifier(double base, double perLevel, double step, double cap, @NotNull ModifierAction action) {
this.setBase(base);
this.setPerLevel(perLevel);
this.setStep(step);
this.setCap(cap);
this.setAction(action);
}
@NotNull
public static Modifier add(double base, double perLevel, double step) {
return add(base, perLevel, step, -1);
}
@NotNull
public static Modifier multiply(double base, double perLevel, double step) {
return multiply(base, perLevel, step, -1);
}
@NotNull
public static Modifier add(double base, double perLevel, double step, double cap) {
return new Modifier(base, perLevel, step, cap, ModifierAction.ADD);
}
@NotNull
public static Modifier multiply(double base, double perLevel, double step, double cap) {
return new Modifier(base, perLevel, step, cap, ModifierAction.MULTIPLY);
}
@NotNull
public static Modifier read(@NotNull FileConfig cfg, @NotNull String path, @NotNull Modifier def, String ... comments) {
return new ConfigValue<>(path,
(cfg2, path2, def2) -> Modifier.read(cfg2, path2),
(cfg2, path2, mod) -> mod.write(cfg2, path2),
def,
comments
).read(cfg);
}
@NotNull
public static Modifier read(@NotNull FileConfig cfg, @NotNull String path) {
double base = ConfigValue.create(path + ".Base", 0D,
"Start modifier value."
).read(cfg);
double perLevel = ConfigValue.create(path + ".Per_Level", 0D,
"Additional value calculated by enchantment level step (see below). Formula: <per_level> * <step>"
).read(cfg);
double step = ConfigValue.create(path + ".Step" , 1D,
"Defines level step for 'Per_Level' value calculation. Formula: <enchant_level> / <step>"
).read(cfg);
double cap = ConfigValue.create(path + ".Cap", -1,
"Sets a limit for the final (base & per level calculations) value.",
"Set '-1' for no limit."
).read(cfg);
ModifierAction action = ConfigValue.create(path + ".Action", ModifierAction.class, ModifierAction.ADD,
"Sets action performed between 'Base' and final 'Per_Level' values.",
"Available types: " + StringUtil.inlineEnum(ModifierAction.class, ", ")
).read(cfg);
return new Modifier(base, perLevel, step, cap, action);
}
public void write(@NotNull FileConfig cfg, @NotNull String path) {
cfg.set(path + ".Base", this.getBase());
cfg.set(path + ".Per_Level", this.getPerLevel());
cfg.set(path + ".Step", this.getStep());
cfg.set(path + ".Cap", this.getCap());
cfg.set(path + ".Action", this.getAction().name());
}
public double getValue(int level) {
if (/*level == 1 || */this.perLevel == 0D) return this.capValue(this.getBase());
//level -= 1;
double step = this.getStep() == 0D ? 1D : Math.floor((double) level / this.getStep());
double result = this.action.math(this.getBase(), this.getPerLevel() * step);
return this.capValue(result);
}
public double capValue(double result) {
return this.cap > 0 ? Math.min(result, this.cap) : result;
}
public int getIntValue(int level) {
return (int) this.getValue(level);
}
public double getBase() {
return this.base;
}
public void setBase(double base) {
this.base = base;
}
public double getPerLevel() {
return this.perLevel;
}
public void setPerLevel(double perLevel) {
this.perLevel = perLevel;
}
public double getStep() {
return step;
}
public void setStep(double step) {
this.step = step;
}
public double getCap() {
return cap;
}
public void setCap(double cap) {
this.cap = cap;
}
@NotNull
public ModifierAction getAction() {
return this.action;
}
public void setAction(@NotNull ModifierAction action) {
this.action = action;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.enchantment.util;
package su.nightexpress.excellentenchants.api;
import org.jetbrains.annotations.NotNull;

View File

@ -0,0 +1,193 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.World;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.distribution.DistributionOptions;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.Lists;
import su.nightexpress.nightcore.util.placeholder.PlaceholderMap;
import java.util.List;
import java.util.Set;
public interface EnchantmentData {
@NotNull PlaceholderMap getPlaceholders(int level);
@NotNull FileConfig getConfig();
boolean load();
boolean checkServerRequirements();
boolean isAvailableToUse(@NotNull LivingEntity entity);
boolean isAvailableToUse(@NotNull World world);
boolean checkEnchantCategory(@NotNull ItemStack item);
boolean checkItemCategory(@NotNull ItemStack item);
@NotNull DistributionOptions getDistributionOptions();
@NotNull Rarity getRarity();
void setRarity(@NotNull Rarity rarity);
@NotNull String getId();
@NotNull String getName();
@NotNull
default String getNameFormatted(int level) {
return this.getNameFormatted(level, -1);
}
@NotNull String getNameFormatted(int level, int charges);
@NotNull List<String> getDescription();
@NotNull List<String> getDescriptionFormatted();
@NotNull List<String> getDescriptionReplaced(int level);
@NotNull EnchantmentTarget getCategory();
@NotNull Enchantment getEnchantment();
void setEnchantment(@NotNull Enchantment enchantment);
ItemCategory[] getItemCategories();
EquipmentSlot[] getSlots();
default boolean hasConflicts() {
return !this.getConflicts().isEmpty();
}
@NotNull Set<String> getConflicts();
int getMinLevel();
int getMaxLevel();
//int getMaxMergeLevel();
//int getAnvilMergeCost(int level);
int getMinCost(int level);
int getMaxCost(int level);
default boolean isCurse() {
return false;
}
boolean isTreasure();
boolean hasVisualEffects();
boolean isChargesEnabled();
boolean isChargesCustomFuel();
int getChargesMax(int level);
int getChargesConsumeAmount(int level);
int getChargesRechargeAmount(int level);
@NotNull ItemStack getChargesFuel();
boolean isChargesFuel(@NotNull ItemStack item);
default int getCharges(@NotNull ItemStack item) {
ItemMeta meta = item.getItemMeta();
return meta == null ? 0 : this.getCharges(meta);
}
int getCharges(@NotNull ItemMeta meta);
void setCharges(@NotNull ItemStack item, int level, int amount);
boolean isFullOfCharges(@NotNull ItemStack item);
boolean isOutOfCharges(@NotNull ItemStack item);
void restoreCharges(@NotNull ItemStack item, int level);
void fuelCharges(@NotNull ItemStack item, int level);
void consumeCharges(@NotNull ItemStack item, int level);
void consumeChargesNoUpdate(@NotNull ItemStack item, int level);
void setDisplayName(@NotNull String displayName);
default void setDescription(@NotNull String... description) {
this.setDescription(Lists.newList(description));
}
void setDescription(@NotNull List<String> description);
boolean isHiddenFromList();
void setHiddenFromList(boolean hiddenFromList);
void setTreasure(boolean treasure);
void setStartLevel(int levelMin);
void setMaxLevel(int levelMax);
//void setMaxMergeLevel(int maxMergeLevel);
@NotNull Modifier getMinCost();
void setMinCost(@NotNull Modifier minCost);
@NotNull Modifier getMaxCost();
void setMaxCost(@NotNull Modifier maxCost);
//@NotNull Modifier getAnvilMergeCost();
//void setAnvilMergeCost(@NotNull Modifier anvilMergeCost);
default void setConflicts(@NotNull String... conflicts) {
this.setConflicts(Lists.newSet(conflicts));
}
void setConflicts(@NotNull Set<String> conflicts);
void setVisualEffects(boolean visualEffects);
void setChargesEnabled(boolean chargesEnabled);
void setChargesCustomFuel(boolean chargesCustomFuel);
@NotNull Modifier getChargesMax();
void setChargesMax(@NotNull Modifier chargesMax);
void setChargesFuel(@Nullable ItemStack chargesFuel);
@NotNull Modifier getChargesConsumeAmount();
void setChargesConsumeAmount(@NotNull Modifier chargesConsumeAmount);
@NotNull Modifier getChargesRechargeAmount();
void setChargesRechargeAmount(@NotNull Modifier chargesRechargeAmount);
}

View File

@ -1,94 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.Keyed;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import java.util.List;
import java.util.Set;
public interface IEnchantment extends Keyed {
boolean isAvailableToUse(@NotNull LivingEntity entity);
@NotNull JYML getConfig();
@NotNull String getId();
@NotNull String getDisplayName();
@NotNull String getNameFormatted(int level);
@NotNull String getNameFormatted(int level, int charges);
@NotNull List<String> getDescription();
@NotNull List<String> getDescription(int level);
@NotNull Set<String> getConflicts();
@NotNull ITier getTier();
@NotNull EnchantmentTarget getCategory();
ItemCategory[] getFitItemTypes();
int getMaxLevel();
int getStartLevel();
int getLevelByEnchantCost(int expLevel);
double getObtainChance(@NotNull ObtainType obtainType);
int getObtainLevelMin(@NotNull ObtainType obtainType);
int getObtainLevelMax(@NotNull ObtainType obtainType);
int generateLevel(@NotNull ObtainType obtainType);
int getAnvilMergeCost(int level);
//@Deprecated
//boolean conflictsWith(@NotNull Enchantment enchantment);
boolean checkEnchantCategory(@NotNull ItemStack item);
boolean checkItemCategory(@NotNull ItemStack item);
boolean isCurse();
boolean isTreasure();
boolean isTradeable();
boolean isDiscoverable();
boolean isChargesEnabled();
int getChargesMax(int level);
int getChargesConsumeAmount(int level);
int getChargesRechargeAmount(int level);
@NotNull ItemStack getChargesFuel();
boolean isChargesFuel(@NotNull ItemStack item);
int getCharges(@NotNull ItemStack item);
boolean isFullOfCharges(@NotNull ItemStack item);
boolean isOutOfCharges(@NotNull ItemStack item);
void consumeCharges(@NotNull ItemStack item, int level);
void consumeChargesNoUpdate(@NotNull ItemStack item, int level);
EquipmentSlot[] getSlots();
}

View File

@ -1,21 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.placeholder.Placeholder;
import java.util.Map;
public interface ITier extends Placeholder {
@NotNull String getId();
int getPriority();
@NotNull String getName();
@NotNull String getColor();
@NotNull Map<ObtainType, Double> getChance();
double getChance(@NotNull ObtainType obtainType);
}

View File

@ -3,7 +3,7 @@ package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.ItemUtil;
import su.nightexpress.nightcore.util.ItemUtil;
import java.util.function.Predicate;
@ -24,6 +24,7 @@ public enum ItemCategory {
PICKAXE(ItemUtil::isPickaxe),
SHOVEL(ItemUtil::isShovel),
FISHING_ROD(ItemUtil::isFishingRod),
SHIELD(itemStack -> itemStack.getType() == Material.SHIELD),
//@Deprecated WEAPON(item -> SWORD.isIncluded(item) || TRIDENT.isIncluded(item)),
TOOL(ItemUtil::isTool),
@ -46,83 +47,7 @@ public enum ItemCategory {
this.predicate = predicate;
}
@Deprecated
public void patchPredicate(@NotNull Predicate<ItemStack> extra) {
//this.setPredicate(item -> this.getPredicate().test(item) || (extra.test(item)));
}
/*public EquipmentSlot[] getSlots() {
return switch (this) {
case BOW, CROSSBOW, TRIDENT, FISHING_ROD, WEAPON, TOOL, HOE, PICKAXE, AXE, SWORD, SHOVEL ->
new EquipmentSlot[]{EquipmentSlot.HAND};
case HELMET -> new EquipmentSlot[]{EquipmentSlot.HEAD};
case CHESTPLATE, ELYTRA -> new EquipmentSlot[]{EquipmentSlot.CHEST};
case LEGGINGS -> new EquipmentSlot[]{EquipmentSlot.LEGS};
case BOOTS -> new EquipmentSlot[]{EquipmentSlot.FEET};
case ARMOR -> new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
case UNIVERSAL -> new EquipmentSlot[]{EquipmentSlot.HAND, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
};
}
@NotNull
public EnchantmentTarget getEnchantmentTarget() {
return switch (this) {
case ARMOR -> EnchantmentTarget.ARMOR;
case BOOTS -> EnchantmentTarget.ARMOR_FEET;
case LEGGINGS -> EnchantmentTarget.ARMOR_LEGS;
case CHESTPLATE, ELYTRA -> EnchantmentTarget.ARMOR_TORSO;
case HELMET -> EnchantmentTarget.ARMOR_HEAD;
case WEAPON, SWORD -> EnchantmentTarget.WEAPON;
case TOOL, AXE, HOE, SHOVEL, PICKAXE -> EnchantmentTarget.TOOL;
case BOW -> EnchantmentTarget.BOW;
case FISHING_ROD -> EnchantmentTarget.FISHING_ROD;
case TRIDENT -> EnchantmentTarget.TRIDENT;
case CROSSBOW -> EnchantmentTarget.CROSSBOW;
case UNIVERSAL -> EnchantmentTarget.WEARABLE;
};
}
@NotNull
public static FitItemType getByEnchantmentTarget(@NotNull EnchantmentTarget target) {
return switch (target) {
case ARMOR -> ARMOR;
case ARMOR_FEET -> BOOTS;
case ARMOR_LEGS -> LEGGINGS;
case ARMOR_TORSO -> CHESTPLATE;
case ARMOR_HEAD -> HELMET;
case WEAPON -> WEAPON;
case TOOL -> TOOL;
case BOW -> BOW;
case FISHING_ROD -> FISHING_ROD;
case TRIDENT -> TRIDENT;
case CROSSBOW -> CROSSBOW;
case BREAKABLE, WEARABLE -> UNIVERSAL;
default -> throw new IllegalStateException("Unexpected value: " + target);
};
}*/
public boolean isIncluded(@NotNull ItemStack item) {
return this.getPredicate().test(item);
/*return switch (this) {
case UNIVERSAL -> ARMOR.isIncluded(item) || WEAPON.isIncluded(item) || TOOL.isIncluded(item) || BOW.isIncluded(item) || FISHING_ROD.isIncluded(item) || ELYTRA.isIncluded(item);
case HELMET -> ItemUtil.isHelmet(item);
case CHESTPLATE -> ItemUtil.isChestplate(item) || (Config.ENCHANTMENTS_ITEM_CHESTPLATE_ENCHANTS_TO_ELYTRA.get() && ELYTRA.isIncluded(item));
case LEGGINGS -> ItemUtil.isLeggings(item);
case BOOTS -> ItemUtil.isBoots(item);
case ELYTRA -> item.getType() == Material.ELYTRA;
case WEAPON -> SWORD.isIncluded(item) || ItemUtil.isTrident(item);
case TOOL -> ItemUtil.isTool(item);
case ARMOR -> ItemUtil.isArmor(item);
case SWORD -> ItemUtil.isSword(item) || (Config.ENCHANTMENTS_ITEM_SWORD_ENCHANTS_TO_AXES.get() && AXE.isIncluded(item));
case TRIDENT -> ItemUtil.isTrident(item);
case AXE -> ItemUtil.isAxe(item);
case BOW -> item.getType() == Material.BOW || (Config.ENCHANTMENTS_ITEM_BOW_ENCHANTS_TO_CROSSBOW.get() && CROSSBOW.isIncluded(item));
case CROSSBOW -> item.getType() == Material.CROSSBOW;
case HOE -> ItemUtil.isHoe(item);
case PICKAXE -> ItemUtil.isPickaxe(item);
case SHOVEL -> ItemUtil.isShovel(item);
case FISHING_ROD -> item.getType() == Material.FISHING_ROD;
};*/
}
}

View File

@ -1,5 +1,11 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.util.random.Rnd;
import java.util.HashMap;
import java.util.Map;
public enum Rarity {
COMMON(10),
@ -7,7 +13,7 @@ public enum Rarity {
RARE(2),
VERY_RARE(1);
private final int weight;
private int weight;
Rarity(int weight) {
this.weight = weight;
@ -16,4 +22,19 @@ public enum Rarity {
public int getWeight() {
return this.weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@NotNull
public static Rarity getByWeight() {
Map<Rarity, Double> map = new HashMap<>();
for (Rarity rarity : Rarity.values()) {
map.put(rarity, (double) rarity.getWeight());
}
return Rnd.getByWeight(map);
}
}

View File

@ -0,0 +1,14 @@
package su.nightexpress.excellentenchants.api.enchantment.data;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public interface ArrowData {
@NotNull ArrowSettings getArrowSettings();
@NotNull
default UniParticle getProjectileTrail() {
return this.getArrowSettings().getProjectileTrail();
}
}

View File

@ -0,0 +1,9 @@
package su.nightexpress.excellentenchants.api.enchantment.data;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public interface ArrowSettings {
@NotNull UniParticle getProjectileTrail();
}

View File

@ -1,10 +1,10 @@
package su.nightexpress.excellentenchants.api.enchantment.meta;
package su.nightexpress.excellentenchants.api.enchantment.data;
import org.jetbrains.annotations.NotNull;
public interface Chanced {
public interface ChanceData {
@NotNull Chanced getChanceImplementation();
@NotNull ChanceSettings getChanceSettings();
/*@NotNull
default UnaryOperator<String> replacePlaceholders(int level) {
@ -12,10 +12,10 @@ public interface Chanced {
}*/
default double getTriggerChance(int level) {
return this.getChanceImplementation().getTriggerChance(level);
return this.getChanceSettings().getTriggerChance(level);
}
default boolean checkTriggerChance(int level) {
return getChanceImplementation().checkTriggerChance(level);
return getChanceSettings().checkTriggerChance(level);
}
}

View File

@ -0,0 +1,8 @@
package su.nightexpress.excellentenchants.api.enchantment.data;
public interface ChanceSettings {
double getTriggerChance(int level);
boolean checkTriggerChance(int level);
}

View File

@ -0,0 +1,24 @@
package su.nightexpress.excellentenchants.api.enchantment.data;
import org.jetbrains.annotations.NotNull;
public interface PeriodicData {
@NotNull PeriodicSettings getPeriodSettings();
default long getInterval() {
return this.getPeriodSettings().getInterval();
}
default long getNextTriggerTime() {
return this.getPeriodSettings().getNextTriggerTime();
}
default boolean isTriggerTime() {
return this.getPeriodSettings().isTriggerTime();
}
default void updateTriggerTime() {
this.getPeriodSettings().updateTriggerTime();
}
}

View File

@ -0,0 +1,12 @@
package su.nightexpress.excellentenchants.api.enchantment.data;
public interface PeriodicSettings {
long getInterval();
long getNextTriggerTime();
boolean isTriggerTime();
void updateTriggerTime();
}

View File

@ -0,0 +1,35 @@
package su.nightexpress.excellentenchants.api.enchantment.data;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
public interface PotionData {
@NotNull PotionSettings getPotionSettings();
default boolean isPermanent() {
return this.getPotionSettings().isPermanent();
}
default PotionEffectType getEffectType() {
return this.getPotionSettings().getEffectType();
}
default int getEffectAmplifier(int level) {
return this.getPotionSettings().getEffectAmplifier(level);
}
default int getEffectDuration(int level) {
return this.getPotionSettings().getEffectDuration(level);
}
default PotionEffect createEffect(int level) {
return this.getPotionSettings().createEffect(level);
}
default boolean addEffect(@NotNull LivingEntity target, int level) {
return this.getPotionSettings().addEffect(target, level);
}
}

View File

@ -0,0 +1,21 @@
package su.nightexpress.excellentenchants.api.enchantment.data;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
public interface PotionSettings {
boolean isPermanent();
PotionEffectType getEffectType();
int getEffectAmplifier(int level);
int getEffectDuration(int level);
PotionEffect createEffect(int level);
boolean addEffect(@NotNull LivingEntity target, int level);
}

View File

@ -0,0 +1,9 @@
package su.nightexpress.excellentenchants.api.enchantment.distribution;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.config.FileConfig;
public interface DistributionOptions {
void load(@NotNull FileConfig config);
}

View File

@ -0,0 +1,12 @@
package su.nightexpress.excellentenchants.api.enchantment.distribution;
public interface VanillaOptions extends DistributionOptions {
boolean isDiscoverable();
void setDiscoverable(boolean discoverable);
boolean isTradeable();
void setTradeable(boolean tradeable);
}

View File

@ -5,9 +5,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface BlockBreakEnchant extends IEnchantment {
public interface BlockBreakEnchant extends EnchantmentData {
boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level);

View File

@ -5,9 +5,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface BlockDropEnchant extends IEnchantment {
public interface BlockDropEnchant extends EnchantmentData {
boolean onDrop(@NotNull BlockDropItemEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level);

View File

@ -8,9 +8,9 @@ import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface BowEnchant extends IEnchantment {
public interface BowEnchant extends EnchantmentData {
boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level);

View File

@ -5,9 +5,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface CombatEnchant extends IEnchantment {
public interface CombatEnchant extends EnchantmentData {
boolean onAttack(@NotNull EntityDamageByEntityEvent event,
@NotNull LivingEntity damager, @NotNull LivingEntity victim,

View File

@ -5,9 +5,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface DamageEnchant extends IEnchantment {
public interface DamageEnchant extends EnchantmentData {
boolean onDamage(@NotNull EntityDamageEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level);

View File

@ -7,9 +7,9 @@ import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityResurrectEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface DeathEnchant extends IEnchantment {
public interface DeathEnchant extends EnchantmentData {
boolean onDeath(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, ItemStack item, int level);

View File

@ -4,9 +4,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface FishingEnchant extends IEnchantment {
public interface FishingEnchant extends EnchantmentData {
boolean onFishing(@NotNull PlayerFishEvent event, @NotNull ItemStack item, int level);

View File

@ -0,0 +1,7 @@
package su.nightexpress.excellentenchants.api.enchantment.type;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface GenericEnchant extends EnchantmentData {
}

View File

@ -5,9 +5,9 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
public interface InteractEnchant extends IEnchantment {
public interface InteractEnchant extends EnchantmentData {
boolean onInteract(@NotNull PlayerInteractEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level);

View File

@ -3,10 +3,10 @@ package su.nightexpress.excellentenchants.api.enchantment.type;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.meta.Periodic;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicData;
public interface PassiveEnchant extends IEnchantment, Periodic {
public interface PassiveEnchant extends EnchantmentData, PeriodicData {
boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level);
}

View File

@ -5,15 +5,16 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>3.6.5</version>
<version>4.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Core</artifactId>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
@ -54,7 +55,7 @@
<dependency>
<groupId>io.lumine</groupId>
<artifactId>Mythic-Dist</artifactId>
<version>5.0.1-SNAPSHOT</version>
<version>5.6.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@ -72,37 +73,32 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>API</artifactId>
<version>3.6.5</version>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>3.6.5</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_18_R2</artifactId>
<version>3.6.5</version>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_19_R3</artifactId>
<version>3.6.5</version>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_20_R1</artifactId>
<version>3.6.5</version>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_20_R2</artifactId>
<version>3.6.5</version>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_20_R3</artifactId>
<version>3.6.5</version>
<version>4.0.0</version>
</dependency>
</dependencies>

View File

@ -1,20 +0,0 @@
package su.nightexpress.excellentenchants;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.tier.TierManager;
public class ExcellentEnchantsAPI {
public static final ExcellentEnchants PLUGIN = ExcellentEnchants.getPlugin(ExcellentEnchants.class);
@NotNull
public static EnchantManager getEnchantManager() {
return PLUGIN.getEnchantManager();
}
@NotNull
public static TierManager getTierManager() {
return PLUGIN.getTierManager();
}
}

View File

@ -1,20 +1,19 @@
package su.nightexpress.excellentenchants;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Item;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.NexPlugin;
import su.nexmedia.engine.Version;
import su.nexmedia.engine.api.command.GeneralCommand;
import su.nexmedia.engine.command.list.ReloadSubCommand;
import su.nexmedia.engine.utils.EngineUtils;
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
import su.nightexpress.excellentenchants.api.DistributionWay;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.command.BookCommand;
import su.nightexpress.excellentenchants.command.EnchantCommand;
import su.nightexpress.excellentenchants.command.ListCommand;
import su.nightexpress.excellentenchants.command.TierbookCommand;
import su.nightexpress.excellentenchants.command.RarityBookCommand;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.config.Keys;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.EnchantPopulator;
@ -23,38 +22,38 @@ import su.nightexpress.excellentenchants.hook.HookId;
import su.nightexpress.excellentenchants.hook.impl.PlaceholderHook;
import su.nightexpress.excellentenchants.hook.impl.ProtocolHook;
import su.nightexpress.excellentenchants.nms.EnchantNMS;
import su.nightexpress.excellentenchants.nms.v1_18_R2.V1_18_R2;
import su.nightexpress.excellentenchants.nms.v1_19_R3.V1_19_R3;
import su.nightexpress.excellentenchants.nms.v1_20_R1.V1_20_R1;
import su.nightexpress.excellentenchants.nms.v1_20_R2.V1_20_R2;
import su.nightexpress.excellentenchants.nms.v1_20_R3.V1_20_R3;
import su.nightexpress.excellentenchants.tier.TierManager;
import su.nightexpress.nightcore.NightPlugin;
import su.nightexpress.nightcore.command.api.NightPluginCommand;
import su.nightexpress.nightcore.command.base.ReloadSubCommand;
import su.nightexpress.nightcore.config.PluginDetails;
import su.nightexpress.nightcore.util.Plugins;
import su.nightexpress.nightcore.util.Version;
public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
// TODO Config option to use minecraft internal enchanting population
// TODO Custom name format for curse enchants
// TODO Custom name format for treasure enchants
public class ExcellentEnchantsPlugin extends NightPlugin {
private EnchantRegistry registry;
private EnchantManager enchantManager;
private EnchantNMS enchantNMS;
private TierManager tierManager;
@Override
@NotNull
protected ExcellentEnchants getSelf() {
return this;
}
@Override
public void onLoad() {
super.onLoad();
//this.updateFitItemTypes();
this.registry = new EnchantRegistry(this);
}
@Override
@NotNull
protected PluginDetails getDefaultDetails() {
return PluginDetails.create("Enchants", new String[]{"excellentenchants", "eenchants"})
.setConfigClass(Config.class)
.setLangClass(Lang.class)
.setPermissionsClass(Perms.class);
}
@Override
public void enable() {
if (!this.setNMS()) {
@ -63,8 +62,15 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
return;
}
this.tierManager = new TierManager(this);
this.tierManager.setup();
Keys.loadKeys(this);
Config.loadRarityWeights(this.getConfig());
this.getLangManager().loadEnum(ItemCategory.class);
this.getLangManager().loadEnum(EnchantmentTarget.class);
this.getLangManager().loadEnum(DistributionWay.class);
this.getLangManager().loadEnum(Rarity.class);
this.registerCommands();
this.registry.setup();
@ -72,14 +78,18 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
this.enchantManager.setup();
if (Config.ENCHANTMENTS_DISPLAY_MODE.get() == 2) {
if (EngineUtils.hasPlugin(HookId.PROTOCOL_LIB)) {
ProtocolHook.setup();
if (Plugins.isInstalled(HookId.PROTOCOL_LIB)) {
ProtocolHook.setup(this);
}
else {
this.warn(HookId.PROTOCOL_LIB + " is not installed. Set display mode to Plain lore.");
this.warn(HookId.PROTOCOL_LIB + " is not installed. Display mode is set to Plain lore.");
Config.ENCHANTMENTS_DISPLAY_MODE.set(1);
}
}
if (Plugins.hasPlaceholderAPI()) {
PlaceholderHook.setup(this);
}
}
@Override
@ -88,19 +98,16 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
this.enchantManager.shutdown();
this.enchantManager = null;
}
if (this.tierManager != null) {
this.tierManager.shutdown();
this.tierManager = null;
}
if (EngineUtils.hasPlaceholderAPI()) {
if (Plugins.hasPlaceholderAPI()) {
PlaceholderHook.shutdown();
}
this.registry.shutdown();
}
private boolean setNMS() {
this.enchantNMS = switch (Version.getCurrent()) {
case V1_18_R2 -> new V1_18_R2();
case V1_19_R3 -> new V1_19_R3();
case V1_20_R1 -> new V1_20_R1();
case V1_20_R2 -> new V1_20_R2();
@ -110,49 +117,27 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
return this.enchantNMS != null;
}
@Override
public void loadConfig() {
this.getConfig().initializeOptions(Config.class);
}
@Override
public void loadLang() {
this.getLangManager().loadMissing(Lang.class);
this.getLangManager().loadEnum(ItemCategory.class);
this.getLangManager().loadEnum(EnchantmentTarget.class);
this.getLangManager().loadEnum(ObtainType.class);
this.getLang().saveChanges();
}
@Override
public void registerCommands(@NotNull GeneralCommand<ExcellentEnchants> mainCommand) {
private void registerCommands() {
NightPluginCommand mainCommand = this.getBaseCommand();
mainCommand.addChildren(new BookCommand(this));
mainCommand.addChildren(new EnchantCommand(this));
mainCommand.addChildren(new ListCommand(this));
mainCommand.addChildren(new TierbookCommand(this));
mainCommand.addChildren(new ReloadSubCommand<>(this, Perms.COMMAND_RELOAD));
}
@Override
public void registerHooks() {
if (EngineUtils.hasPlaceholderAPI()) {
PlaceholderHook.setup(this);
}
}
@Override
public void registerPermissions() {
this.registerPermissions(Perms.class);
mainCommand.addChildren(new RarityBookCommand(this));
mainCommand.addChildren(new ReloadSubCommand(this, Perms.COMMAND_RELOAD));
}
@NotNull
public EnchantPopulator createPopulator(@NotNull ItemStack item, @NotNull ObtainType obtainType) {
return new EnchantPopulator(this, item, obtainType);
public EnchantPopulator createPopulator(@NotNull ItemStack item, @NotNull DistributionWay distributionWay) {
return new EnchantPopulator(this, item, distributionWay);
}
@NotNull
public TierManager getTierManager() {
return tierManager;
public void populateResource(@NotNull BlockDropItemEvent event, @NotNull ItemStack itemStack) {
/*if (Plugins.isSpigot()) {
this.warn("Adding items to BlockDropItemEvent is not supported in Spigot, please use Paper or its forks for this feature.");
return;
}*/
Item item = this.getEnchantNMS().popResource(event.getBlock(), itemStack);
event.getItems().add(item);
}
@NotNull

View File

@ -1,25 +1,31 @@
package su.nightexpress.excellentenchants;
import org.bukkit.permissions.PermissionDefault;
import su.nexmedia.engine.api.server.JPermission;
import su.nightexpress.nightcore.util.wrapper.UniPermission;
public class Perms {
private static final String PREFIX = "excellentenchants.";
private static final String PREFIX = "excellentenchants.";
private static final String PREFIX_COMMAND = PREFIX + "command.";
public static final JPermission PLUGIN = new JPermission(PREFIX + Placeholders.WILDCARD, "Access to all the plugin functions.");
public static final JPermission COMMAND = new JPermission(PREFIX_COMMAND + Placeholders.WILDCARD, "Access to all the plugin commands.");
public static final UniPermission PLUGIN = new UniPermission(PREFIX + Placeholders.WILDCARD, "Access to all the plugin functions.");
public static final UniPermission COMMAND = new UniPermission(PREFIX_COMMAND + Placeholders.WILDCARD, "Access to all the plugin commands.");
public static final JPermission COMMAND_BOOK = new JPermission(PREFIX_COMMAND + "book", "Allows to use '/eenchants book' command.");
public static final JPermission COMMAND_ENCHANT = new JPermission(PREFIX_COMMAND + "enchant", "Allows to use '/eenchants enchant' command.");
public static final JPermission COMMAND_LIST = new JPermission(PREFIX_COMMAND + "list", "Allows to use '/eenchants list' command.", PermissionDefault.TRUE);
public static final JPermission COMMAND_TIERBOOK = new JPermission(PREFIX_COMMAND + "tierbook", "Allows to use '/eenchants tierbook' command.");
public static final JPermission COMMAND_RELOAD = new JPermission(PREFIX_COMMAND + "reload", "Allows to use '/eenchants reload' command.");
public static final UniPermission COMMAND_BOOK = new UniPermission(PREFIX_COMMAND + "book");
public static final UniPermission COMMAND_ENCHANT = new UniPermission(PREFIX_COMMAND + "enchant");
public static final UniPermission COMMAND_LIST = new UniPermission(PREFIX_COMMAND + "list", "Allows to use '/eenchants list' command.", PermissionDefault.TRUE);
public static final UniPermission COMMAND_RARITY_BOOK = new UniPermission(PREFIX_COMMAND + "raritybook");
public static final UniPermission COMMAND_RELOAD = new UniPermission(PREFIX_COMMAND + "reload");
static {
PLUGIN.addChildren(COMMAND);
COMMAND.addChildren(COMMAND_BOOK, COMMAND_ENCHANT, COMMAND_LIST, COMMAND_RELOAD, COMMAND_TIERBOOK);
COMMAND.addChildren(
COMMAND_BOOK,
COMMAND_ENCHANT,
COMMAND_LIST,
COMMAND_RELOAD,
COMMAND_RARITY_BOOK
);
}
}

View File

@ -1,54 +1,56 @@
/*
* Decompiled with CFR 0.151.
*
* Could not load the following classes:
* su.nexmedia.engine.utils.Placeholders
*/
package su.nightexpress.excellentenchants;
public class Placeholders
extends su.nexmedia.engine.utils.Placeholders {
public static final String URL_WIKI = "https://github.com/nulli0n/ExcellentEnchants-spigot/wiki/";
public class Placeholders extends su.nightexpress.nightcore.util.Placeholders {
public static final String URL_WIKI = "https://github.com/nulli0n/ExcellentEnchants-spigot/wiki/";
public static final String URL_PLACEHOLDERS = "https://github.com/nulli0n/ExcellentEnchants-spigot/wiki/Internal-Placeholders";
public static final String URL_ENGINE_SCALER = "https://github.com/nulli0n/NexEngine-spigot/wiki/Configuration-Tips#scalable-sections";
public static final String URL_ENGINE_ITEMS = "https://github.com/nulli0n/NexEngine-spigot/wiki/Configuration-Tips#item-sections";
public static final String GENERIC_TYPE = "%type%";
public static final String GENERIC_NAME = "%name%";
public static final String GENERIC_ITEM = "%item%";
public static final String GENERIC_LEVEL = "%level%";
public static final String GENERIC_AMOUNT = "%amount%";
public static final String URL_CHRAGES = "https://github.com/nulli0n/ExcellentEnchants-spigot/wiki/Charges-System";
public static final String VANILLA_DISTRIBUTION_NAME = "Vanilla Distribution Mode";
public static final String CUSTOM_DISTRIBUTION_NAME = "Custom Distribution Mode";
public static final String VANILLA_DISTRIBUTION_HEADER = "=".repeat(15) + " " + VANILLA_DISTRIBUTION_NAME + " " + "=".repeat(15);
public static final String CUSTOM_DISTRIBUTION_HEADER = "=".repeat(15) + " " + CUSTOM_DISTRIBUTION_NAME + " " + "=".repeat(15);
public static final String GENERIC_TYPE = "%type%";
public static final String GENERIC_NAME = "%name%";
public static final String GENERIC_ITEM = "%item%";
public static final String GENERIC_LEVEL = "%level%";
public static final String GENERIC_AMOUNT = "%amount%";
public static final String GENERIC_DESCRIPTION = "%description%";
public static final String GENERIC_ENCHANT = "%enchant%";
public static final String ENCHANTMENT_CHANCE = "%enchantment_trigger_chance%";
public static final String ENCHANTMENT_INTERVAL = "%enchantment_trigger_interval%";
public static final String ENCHANTMENT_POTION_LEVEL = "%enchantment_potion_level%";
public static final String ENCHANTMENT_POTION_DURATION = "%enchantment_potion_duration%";
public static final String ENCHANTMENT_POTION_TYPE = "%enchantment_potion_type%";
public static final String ENCHANTMENT_ID = "%enchantment_id%";
public static final String ENCHANTMENT_NAME = "%enchantment_name%";
public static final String ENCHANTMENT_NAME_FORMATTED = "%enchantment_name_formatted%";
public static final String ENCHANTMENT_DESCRIPTION = "%enchantment_description%";
public static final String ENCHANTMENT_LEVEL = "%enchantment_level%";
public static final String ENCHANTMENT_LEVEL_MIN = "%enchantment_level_min%";
public static final String ENCHANTMENT_LEVEL_MAX = "%enchantment_level_max%";
public static final String ENCHANTMENT_TIER = "%enchantment_tier%";
public static final String ENCHANTMENT_TIER_COLOR = "%enchantment_tier_color%";
public static final String ENCHANTMENT_FIT_ITEM_TYPES = "%enchantment_fit_item_types%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING = "%enchantment_obtain_chance_enchanting%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_VILLAGER = "%enchantment_obtain_chance_villager%";
public static final String GENERIC_ENCHANT = "%enchant%";
public static final String GENERIC_RADIUS = "%radius%";
public static final String GENERIC_DURATION = "%duration%";
public static final String GENERIC_DAMAGE = "%damage%";
public static final String GENERIC_MIN = "%min%";
public static final String GENERIC_MAX = "%max%";
public static final String GENERIC_TIME = "%time%";
public static final String ENCHANTMENT_CHANCE = "%enchantment_trigger_chance%";
public static final String ENCHANTMENT_INTERVAL = "%enchantment_trigger_interval%";
public static final String ENCHANTMENT_POTION_LEVEL = "%enchantment_potion_level%";
public static final String ENCHANTMENT_POTION_DURATION = "%enchantment_potion_duration%";
public static final String ENCHANTMENT_POTION_TYPE = "%enchantment_potion_type%";
public static final String ENCHANTMENT_ID = "%enchantment_id%";
public static final String ENCHANTMENT_NAME = "%enchantment_name%";
public static final String ENCHANTMENT_NAME_FORMATTED = "%enchantment_name_formatted%";
public static final String ENCHANTMENT_DESCRIPTION = "%enchantment_description%";
public static final String ENCHANTMENT_DESCRIPTION_FORMATTED = "%enchantment_description_formatted%";
public static final String ENCHANTMENT_DESCRIPTION_REPLACED = "%enchantment_description_replaced%";
public static final String ENCHANTMENT_LEVEL = "%enchantment_level%";
public static final String ENCHANTMENT_LEVEL_MIN = "%enchantment_level_min%";
public static final String ENCHANTMENT_LEVEL_MAX = "%enchantment_level_max%";
public static final String ENCHANTMENT_RARITY = "%enchantment_rarity%";
public static final String ENCHANTMENT_FIT_ITEM_TYPES = "%enchantment_fit_item_types%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING = "%enchantment_obtain_chance_enchanting%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_VILLAGER = "%enchantment_obtain_chance_villager%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_LOOT_GENERATION = "%enchantment_obtain_chance_loot_generation%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_FISHING = "%enchantment_obtain_chance_fishing%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_MOB_SPAWNING = "%enchantment_obtain_chance_mob_spawning%";
public static final String ENCHANTMENT_CHARGES_MAX_AMOUNT = "%enchantment_charges_max_amount%";
public static final String ENCHANTMENT_CHARGES_CONSUME_AMOUNT = "%enchantment_charges_consume_amount%";
public static final String ENCHANTMENT_CHARGES_RECHARGE_AMOUNT = "%enchantment_charges_recharge_amount%";
public static final String ENCHANTMENT_CHARGES_FUEL_ITEM = "%enchantment_charges_fuel_item%";
public static final String TIER_ID = "%tier_id%";
public static final String TIER_NAME = "%tier_name%";
public static final String TIER_OBTAIN_CHANCE_ENCHANTING = "%tier_obtain_chance_enchanting%";
public static final String TIER_OBTAIN_CHANCE_VILLAGER = "%tier_obtain_chance_villager%";
public static final String TIER_OBTAIN_CHANCE_LOOT_GENERATION = "%tier_obtain_chance_loot_generation%";
public static final String TIER_OBTAIN_CHANCE_FISHING = "%tier_obtain_chance_fishing%";
public static final String TIER_OBTAIN_CHANCE_MOB_SPAWNING = "%tier_obtain_chance_mob_spawning%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_FISHING = "%enchantment_obtain_chance_fishing%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_MOB_SPAWNING = "%enchantment_obtain_chance_mob_spawning%";
public static final String ENCHANTMENT_CHARGES = "%enchantment_charges%";
public static final String ENCHANTMENT_CHARGES_MAX_AMOUNT = "%enchantment_charges_max_amount%";
public static final String ENCHANTMENT_CHARGES_CONSUME_AMOUNT = "%enchantment_charges_consume_amount%";
public static final String ENCHANTMENT_CHARGES_RECHARGE_AMOUNT = "%enchantment_charges_recharge_amount%";
public static final String ENCHANTMENT_CHARGES_FUEL_ITEM = "%enchantment_charges_fuel_item%";
}

View File

@ -1,6 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
public interface Cleanable {
void clear();
}

View File

@ -1,83 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.Keyed;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.api.config.JYML;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import su.nightexpress.excellentenchants.tier.Tier;
import java.util.List;
import java.util.Set;
public interface IEnchantment extends Keyed {
boolean isAvailableToUse(@NotNull LivingEntity entity);
@NotNull JYML getConfig();
@NotNull String getId();
@NotNull String getDisplayName();
@NotNull String getNameFormatted(int level);
@NotNull String getNameFormatted(int level, int charges);
@NotNull List<String> getDescription();
@NotNull List<String> getDescription(int level);
@NotNull Set<String> getConflicts();
@NotNull Tier getTier();
int getMaxLevel();
int getStartLevel();
int getLevelByEnchantCost(int expLevel);
double getObtainChance(@NotNull ObtainType obtainType);
int getObtainLevelMin(@NotNull ObtainType obtainType);
int getObtainLevelMax(@NotNull ObtainType obtainType);
int generateLevel(@NotNull ObtainType obtainType);
int getAnvilMergeCost(int level);
boolean conflictsWith(@NotNull Enchantment enchantment);
boolean canEnchantItem(@Nullable ItemStack item);
boolean isCursed();
boolean isTreasure();
boolean isChargesEnabled();
int getChargesMax(int level);
int getChargesConsumeAmount(int level);
int getChargesRechargeAmount(int level);
@NotNull ItemStack getChargesFuel();
boolean isChargesFuel(@NotNull ItemStack item);
int getCharges(@NotNull ItemStack item);
boolean isFullOfCharges(@NotNull ItemStack item);
boolean isOutOfCharges(@NotNull ItemStack item);
void consumeCharges(@NotNull ItemStack item, int level);
void consumeChargesNoUpdate(@NotNull ItemStack item, int level);
}

View File

@ -1,29 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment.meta;
import org.bukkit.entity.Projectile;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import java.util.Optional;
public interface Arrowed {
@NotNull Arrowed getArrowImplementation();
@NotNull
default Optional<UniParticle> getTrailParticle() {
return this.getArrowImplementation().getTrailParticle();
}
default void addTrail(@NotNull Projectile projectile) {
this.getArrowImplementation().addTrail(projectile);
}
default void addData(@NotNull Projectile projectile) {
this.getArrowImplementation().addData(projectile);
}
default boolean isOurProjectile(@NotNull Projectile projectile) {
return this.getArrowImplementation().isOurProjectile(projectile);
}
}

View File

@ -1,24 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment.meta;
import org.jetbrains.annotations.NotNull;
public interface Periodic {
@NotNull Periodic getPeriodImplementation();
default long getInterval() {
return this.getPeriodImplementation().getInterval();
}
default long getNextTriggerTime() {
return this.getPeriodImplementation().getNextTriggerTime();
}
default boolean isTriggerTime() {
return this.getPeriodImplementation().isTriggerTime();
}
default void updateTriggerTime() {
this.getPeriodImplementation().updateTriggerTime();
}
}

View File

@ -1,35 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment.meta;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
public interface Potioned {
@NotNull Potioned getPotionImplementation();
default boolean isPermanent() {
return this.getPotionImplementation().isPermanent();
}
default PotionEffectType getEffectType() {
return this.getPotionImplementation().getEffectType();
}
default int getEffectAmplifier(int level) {
return this.getPotionImplementation().getEffectAmplifier(level);
}
default int getEffectDuration(int level) {
return this.getPotionImplementation().getEffectDuration(level);
}
default PotionEffect createEffect(int level) {
return this.getPotionImplementation().createEffect(level);
}
default boolean addEffect(@NotNull LivingEntity target, int level) {
return this.getPotionImplementation().addEffect(target, level);
}
}

View File

@ -1,7 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment.type;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
public interface GenericEnchant extends IEnchantment {
}

View File

@ -1,42 +1,41 @@
package su.nightexpress.excellentenchants.command;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.command.AbstractCommand;
import su.nexmedia.engine.api.command.CommandResult;
import su.nexmedia.engine.utils.CollectionsUtil;
import su.nexmedia.engine.utils.PlayerUtil;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.Perms;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.command.CommandResult;
import su.nightexpress.nightcore.command.impl.AbstractCommand;
import su.nightexpress.nightcore.util.BukkitThing;
import su.nightexpress.nightcore.util.Players;
import su.nightexpress.nightcore.util.random.Rnd;
import java.util.Arrays;
import java.util.List;
public class BookCommand extends AbstractCommand<ExcellentEnchants> {
public class BookCommand extends AbstractCommand<ExcellentEnchantsPlugin> {
public BookCommand(@NotNull ExcellentEnchants plugin) {
public BookCommand(@NotNull ExcellentEnchantsPlugin plugin) {
super(plugin, new String[]{"book"}, Perms.COMMAND_BOOK);
this.setDescription(plugin.getMessage(Lang.COMMAND_BOOK_DESC));
this.setUsage(plugin.getMessage(Lang.COMMAND_BOOK_USAGE));
this.setDescription(Lang.COMMAND_BOOK_DESC);
this.setUsage(Lang.COMMAND_BOOK_USAGE);
}
@Override
@NotNull
public List<String> getTab(@NotNull Player player, int arg, @NotNull String[] args) {
if (arg == 1) {
return CollectionsUtil.playerNames(player);
return Players.playerNames(player);
}
if (arg == 2) {
return Arrays.stream(Enchantment.values()).map(e -> e.getKey().getKey()).toList();
return BukkitThing.getEnchantments().stream().map(enchantment -> enchantment.getKey().getKey()).toList();
}
if (arg == 3) {
return Arrays.asList("-1", "1", "5", "10");
@ -47,19 +46,19 @@ public class BookCommand extends AbstractCommand<ExcellentEnchants> {
@Override
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
if (result.length() < 4) {
this.printUsage(sender);
this.errorUsage(sender);
return;
}
Player player = PlayerUtil.getPlayer(result.getArg(1));
Player player = Players.getPlayer(result.getArg(1));
if (player == null) {
this.errorPlayer(sender);
return;
}
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(result.getArg(2).toLowerCase()));
Enchantment enchantment = BukkitThing.getEnchantment(result.getArg(2));
if (enchantment == null) {
plugin.getMessage(Lang.ERROR_NO_ENCHANT).send(sender);
Lang.ERROR_NO_ENCHANT.getMessage().send(sender);
return;
}
@ -71,9 +70,9 @@ public class BookCommand extends AbstractCommand<ExcellentEnchants> {
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
EnchantUtils.add(item, enchantment, level, true);
EnchantUtils.updateDisplay(item);
PlayerUtil.addItem(player, item);
Players.addItem(player, item);
plugin.getMessage(Lang.COMMAND_BOOK_DONE)
Lang.COMMAND_BOOK_DONE.getMessage()
.replace(Placeholders.GENERIC_ENCHANT, EnchantUtils.getLocalized(enchantment))
.replace(Placeholders.forPlayer(player))
.send(sender);

View File

@ -1,47 +1,46 @@
package su.nightexpress.excellentenchants.command;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.command.AbstractCommand;
import su.nexmedia.engine.api.command.CommandResult;
import su.nexmedia.engine.utils.*;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.Perms;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.command.CommandResult;
import su.nightexpress.nightcore.command.impl.AbstractCommand;
import su.nightexpress.nightcore.util.*;
import su.nightexpress.nightcore.util.random.Rnd;
import java.util.Arrays;
import java.util.List;
public class EnchantCommand extends AbstractCommand<ExcellentEnchants> {
public class EnchantCommand extends AbstractCommand<ExcellentEnchantsPlugin> {
public EnchantCommand(@NotNull ExcellentEnchants plugin) {
public EnchantCommand(@NotNull ExcellentEnchantsPlugin plugin) {
super(plugin, new String[]{"enchant"}, Perms.COMMAND_ENCHANT);
this.setDescription(plugin.getMessage(Lang.COMMAND_ENCHANT_DESC));
this.setUsage(plugin.getMessage(Lang.COMMAND_ENCHANT_USAGE));
this.setDescription(Lang.COMMAND_ENCHANT_DESC);
this.setUsage(Lang.COMMAND_ENCHANT_USAGE);
}
@Override
@NotNull
public List<String> getTab(@NotNull Player player, int arg, @NotNull String[] args) {
if (arg == 1) {
return Arrays.stream(Enchantment.values()).map(e -> e.getKey().getKey()).toList();
return BukkitThing.getEnchantments().stream().map(enchantment -> enchantment.getKey().getKey()).toList();
}
if (arg == 2) {
return Arrays.asList("-1", "1", "5", "10");
}
if (arg == 3) {
return CollectionsUtil.playerNames(player);
return Players.playerNames(player);
}
if (arg == 4) {
return CollectionsUtil.getEnumsList(EquipmentSlot.class);
return Lists.getEnums(EquipmentSlot.class);
}
return super.getTab(player, arg, args);
}
@ -49,17 +48,17 @@ public class EnchantCommand extends AbstractCommand<ExcellentEnchants> {
@Override
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
if (result.length() < 3) {
this.printUsage(sender);
this.errorUsage(sender);
return;
}
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(result.getArg(1).toLowerCase()));
Enchantment enchantment = BukkitThing.getEnchantment(result.getArg(1));
if (enchantment == null) {
plugin.getMessage(Lang.ERROR_NO_ENCHANT).send(sender);
Lang.ERROR_NO_ENCHANT.getMessage().send(sender);
return;
}
Player player = PlayerUtil.getPlayer(result.getArg(3, sender.getName()));
Player player = Players.getPlayer(result.getArg(3, sender.getName()));
if (player == null) {
this.errorPlayer(sender);
return;
@ -69,7 +68,7 @@ public class EnchantCommand extends AbstractCommand<ExcellentEnchants> {
ItemStack item = player.getInventory().getItem(slot);
if (item == null || item.getType().isAir()) {
this.plugin.getMessage(Lang.COMMAND_ENCHANT_ERROR_NO_ITEM).send(sender);
Lang.COMMAND_ENCHANT_ERROR_NO_ITEM.getMessage().send(sender);
return;
}
@ -86,7 +85,7 @@ public class EnchantCommand extends AbstractCommand<ExcellentEnchants> {
EnchantUtils.updateDisplay(item);
player.getInventory().setItem(slot, item);
plugin.getMessage(sender == player ? Lang.COMMAND_ENCHANT_DONE_SELF : Lang.COMMAND_ENCHANT_DONE_OTHERS)
(sender == player ? Lang.COMMAND_ENCHANT_DONE_SELF : Lang.COMMAND_ENCHANT_DONE_OTHERS).getMessage()
.replace(Placeholders.forPlayer(player))
.replace(Placeholders.GENERIC_ITEM, ItemUtil.getItemName(item))
.replace(Placeholders.GENERIC_ENCHANT, EnchantUtils.getLocalized(enchantment))

View File

@ -3,22 +3,22 @@ package su.nightexpress.excellentenchants.command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.command.AbstractCommand;
import su.nexmedia.engine.api.command.CommandResult;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.Perms;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.nightcore.command.CommandResult;
import su.nightexpress.nightcore.command.impl.AbstractCommand;
public class ListCommand extends AbstractCommand<ExcellentEnchants> {
public class ListCommand extends AbstractCommand<ExcellentEnchantsPlugin> {
public ListCommand(@NotNull ExcellentEnchants plugin) {
public ListCommand(@NotNull ExcellentEnchantsPlugin plugin) {
super(plugin, new String[]{"list"}, Perms.COMMAND_LIST);
this.setDescription(plugin.getMessage(Lang.COMMAND_LIST_DESC));
this.setDescription(Lang.COMMAND_LIST_DESC);
this.setPlayerOnly(true);
}
@Override
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
plugin.getEnchantManager().getEnchantsListGUI().open((Player) sender, 1);
plugin.getEnchantManager().openEnchantsMenu((Player) sender);
}
}

View File

@ -0,0 +1,91 @@
package su.nightexpress.excellentenchants.command;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.Perms;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.command.CommandResult;
import su.nightexpress.nightcore.command.impl.AbstractCommand;
import su.nightexpress.nightcore.util.Lists;
import su.nightexpress.nightcore.util.Players;
import su.nightexpress.nightcore.util.StringUtil;
import su.nightexpress.nightcore.util.random.Rnd;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class RarityBookCommand extends AbstractCommand<ExcellentEnchantsPlugin> {
public RarityBookCommand(@NotNull ExcellentEnchantsPlugin plugin) {
super(plugin, new String[]{"raritybook"}, Perms.COMMAND_RARITY_BOOK);
this.setDescription(Lang.COMMAND_RARITY_BOOK_DESC);
this.setUsage(Lang.COMMAND_RARITY_BOOK_USAGE);
}
@Override
@NotNull
public List<String> getTab(@NotNull Player player, int arg, @NotNull String[] args) {
if (arg == 1) {
return Players.playerNames(player);
}
if (arg == 2) {
return Lists.getEnums(Rarity.class);
}
if (arg == 3) {
return Arrays.asList("-1", "1", "5", "10");
}
return super.getTab(player, arg, args);
}
@Override
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
if (result.length() < 4) {
this.errorUsage(sender);
return;
}
Player player = Players.getPlayer(result.getArg(1));
if (player == null) {
this.errorPlayer(sender);
return;
}
Rarity rarity = StringUtil.getEnum(result.getArg(2), Rarity.class).orElse(null);
if (rarity == null) {
Lang.ERROR_INVALID_RARITY.getMessage().send(sender);
return;
}
Set<EnchantmentData> enchants = EnchantRegistry.getByRarity(rarity);
EnchantmentData enchantmentData = enchants.isEmpty() ? null : Rnd.get(enchants);
if (enchantmentData == null) {
Lang.ERROR_NO_ENCHANT.getMessage().send(sender);
return;
}
int level = result.getInt(3, -1);
if (level < 1) {
level = Rnd.get(enchantmentData.getMinLevel(), enchantmentData.getMaxLevel());
}
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
EnchantUtils.add(item, enchantmentData.getEnchantment(), level, true);
EnchantUtils.updateDisplay(item);
Players.addItem(player, item);
Lang.COMMAND_RARITY_BOOK_DONE.getMessage()
.replace(Placeholders.GENERIC_NAME, plugin.getLangManager().getEnum(rarity))
.replace(Placeholders.forPlayer(player))
.send(sender);
}
}

View File

@ -1,90 +0,0 @@
package su.nightexpress.excellentenchants.command;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.command.AbstractCommand;
import su.nexmedia.engine.api.command.CommandResult;
import su.nexmedia.engine.utils.CollectionsUtil;
import su.nexmedia.engine.utils.Placeholders;
import su.nexmedia.engine.utils.PlayerUtil;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Perms;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.excellentenchants.tier.Tier;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class TierbookCommand extends AbstractCommand<ExcellentEnchants> {
public TierbookCommand(@NotNull ExcellentEnchants plugin) {
super(plugin, new String[]{"tierbook"}, Perms.COMMAND_TIERBOOK);
this.setDescription(plugin.getMessage(Lang.COMMAND_TIER_BOOK_DESC));
this.setUsage(plugin.getMessage(Lang.COMMAND_TIER_BOOK_USAGE));
}
@Override
@NotNull
public List<String> getTab(@NotNull Player player, int arg, @NotNull String[] args) {
if (arg == 1) {
return CollectionsUtil.playerNames(player);
}
if (arg == 2) {
return plugin.getTierManager().getTierIds();
}
if (arg == 3) {
return Arrays.asList("-1", "1", "5", "10");
}
return super.getTab(player, arg, args);
}
@Override
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
if (result.length() < 4) {
this.printUsage(sender);
return;
}
Player player = PlayerUtil.getPlayer(result.getArg(1));
if (player == null) {
this.errorPlayer(sender);
return;
}
Tier tier = plugin.getTierManager().getTierById(result.getArg(2).toLowerCase());
if (tier == null) {
plugin.getMessage(Lang.COMMAND_TIER_BOOK_ERROR).send(sender);
return;
}
Set<ExcellentEnchant> enchants = EnchantRegistry.getOfTier(tier);
ExcellentEnchant enchant = enchants.isEmpty() ? null : Rnd.get(enchants);
if (enchant == null) {
plugin.getMessage(Lang.ERROR_NO_ENCHANT).send(sender);
return;
}
int level = result.getInt(3, -1);
if (level < 1) {
level = Rnd.get(enchant.getStartLevel(), enchant.getMaxLevel());
}
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
EnchantUtils.add(item, enchant.getBackend(), level, true);
EnchantUtils.updateDisplay(item);
PlayerUtil.addItem(player, item);
plugin.getMessage(Lang.COMMAND_TIER_BOOK_DONE)
.replace(tier.replacePlaceholders())
.replace(Placeholders.forPlayer(player))
.send(sender);
}
}

View File

@ -3,166 +3,255 @@ package su.nightexpress.excellentenchants.config;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.Colorizer;
import su.nexmedia.engine.utils.Colors2;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
import su.nightexpress.excellentenchants.tier.Tier;
import su.nightexpress.excellentenchants.api.DistributionMode;
import su.nightexpress.excellentenchants.api.DistributionWay;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.hook.HookId;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.StringUtil;
import su.nightexpress.nightcore.util.wrapper.UniInt;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static su.nightexpress.excellentenchants.Placeholders.*;
import static su.nightexpress.nightcore.util.text.tag.Tags.*;
public class Config {
public static final String DIR_MENU = "/menu/";
public static final String DIR_ENCHANTS = "/enchants/";
public static final JOption<Long> TASKS_ARROW_TRAIL_TICKS_INTERVAL = JOption.create("Tasks.Arrow_Trail.Tick_Interval",
public static final ConfigValue<Long> CORE_PROJECTILE_PARTICLE_INTERVAL = ConfigValue.create("Core.Projectile_Particles_Tick_Interval",
1L,
"Sets how often (in ticks) arrow trail particle effects will be spawned behind the arrow."
"Sets how often (in ticks) enchantment particle effects will be spawned behind projectiles.",
"[Increase for performance; Decrease for better visuals]",
"[20 ticks = 1 second]",
"[Default is 1]"
);
public static final JOption<Long> TASKS_PASSIVE_ENCHANTS_TRIGGER_INTERVAL = JOption.create("Tasks.Passive_Enchants.Trigger_Interval",
public static final ConfigValue<Long> CORE_PASSIVE_ENCHANTS_TRIGGER_INTERVAL = ConfigValue.create("Core.Passive_Enchants_Trigger_Interval",
100L,
"Sets how often (in ticks) the plugin will attempt to trigger passive enchantment effects on all alive entities.",
"For best results it's recommened to keep this value smaller, but at the same rate as enchantment 'Trigger_Interval' settings.",
"Examples:",
"--- Global: 100 ticks; Regrowth: 100 ticks; Saturation: 100 ticks;",
"--- Global: 50 ticks, Regrowth: 100 ticks; Saturation: 150 ticks;"
"Sets how often (in ticks) passive enchantment effects will trigger on all alive and loaded entities.",
"For best results it's recommened to keep this value lower, but at the same rate as enchantment's 'Trigger_Interval' option.",
"=".repeat(15) + " EXAMPLES " + "=".repeat(15),
"==> Global (this): 100 ticks; Regrowth: 200 ticks; Saturation: 300 ticks;",
"==> Global (this): 50 ticks, Regrowth: 100 ticks; Saturation: 150 ticks;",
"[Increase for performance; Decrease for more smooth effect]",
"[20 ticks = 1 second]",
"[Default is 100]"
);
public static final JOption<Boolean> ENCHANTMENTS_INTERNAL_HANDLER = JOption.create("Enchantments.Internal_Distributor", false,
"[EXPERIMENTAL - DO NOT TOUCH]",
"Sets whether or not enchantment distribution will be handled by vanilla server mechanics.");
public static final ConfigValue<Boolean> CORE_PASSIVE_ENCHANTS_FOR_MOBS = ConfigValue.create("Core.Apply_Passive_Enchants_To_Mobs",
true,
"Sets whether or not mobs can have passive enchantment effects (such as permanent potion effects, regeneration, etc.).",
"[Enable for enhanced gameplay; Disable for performance]",
"[Default is true]"
);
public static final JOption<Boolean> ENCHANTMENTS_CHARGES_ENABLED = JOption.create("Enchantments.Charges.Enabled",
public static final ConfigValue<Boolean> CORE_SWORD_ENCHANTS_TO_AXES = ConfigValue.create("Core.Sword_Enchants_To_Axes",
true,
"Sets whether or not Sword enchantments can be applied on Axes.",
"[Default is true]"
);
public static final ConfigValue<Boolean> CORE_BOW_ENCHANTS_TO_CROSSBOW = ConfigValue.create("Core.Bow_Enchants_To_Crossbows",
true,
"Sets whether or not Bow enchantments can be applied on Crossbows.",
"[Default is true]"
);
public static final ConfigValue<Boolean> CORE_CHESTPLATE_ENCHANTS_TO_ELYTRA = ConfigValue.create("Core.Chestplate_Enchants_To_Elytra",
false,
"Enables the enchantment Charges feature.",
Placeholders.URL_WIKI + "Charges-System");
"Sets whether or not Chestplate enchantments can be applied on Elytras.",
"[Default is false]"
);
public static final JOption<TreeMap<Integer, String>> ENCHANTMENTS_CHARGES_FORMAT = new JOption<TreeMap<Integer, String>>("Enchantments.Charges.Format",
(cfg, path, def) -> {
TreeMap<Integer, String> map = new TreeMap<>();
for (String raw : cfg.getSection(path)) {
int percent = StringUtil.getInteger(raw, -1);
if (percent < 0) continue;
String format = Colorizer.apply(cfg.getString(path + "." + raw, ""));
if (format.isEmpty()) continue;
map.put(percent, format);
}
return map;
},
public static final ConfigValue<Set<String>> ENCHANTMENTS_DISABLED_LIST = ConfigValue.forSet("Enchantments.Disabled.List",
String::toLowerCase,
FileConfig::set,
Set.of("example_name", "custom_sharpness"),
"Put here CUSTOM enchantment names that you want to disable and remove completely.",
"Enchantment names are equal to their config file names in '" + DIR_ENCHANTS + "' folder.",
"[*] You MUST REBOOT your server for disabled enchantments to have effect.",
"[*] Once enchantment is disabled, it will be removed from all items in the world on next load!"
);
public static final ConfigValue<Map<String, Set<String>>> ENCHANTMENTS_DISABLED_IN_WORLDS = ConfigValue.forMap("Enchantments.Disabled.ByWorld",
String::toLowerCase,
(cfg, path, worldName) -> cfg.getStringSet(path + "." + worldName).stream().map(String::toLowerCase).collect(Collectors.toSet()),
(cfg, path, map) -> map.forEach((world, enchants) -> cfg.set(path + "." + world, enchants)),
() -> Map.of(
"your_world_name", Set.of("enchantment_name", "ice_aspect"),
"another_world", Set.of("another_enchantment", "ice_aspect")
),
"Put here CUSTOM enchantment names that you want to disable in specific worlds.",
"To disable all enchantments for a world, use '" + WILDCARD + "' instead of enchantment names.",
"Enchantment names are equal to their config file names in '" + DIR_ENCHANTS + "' folder.",
VANILLA_DISTRIBUTION_HEADER,
"Enchantments will have no effect, but will appear in the world.",
CUSTOM_DISTRIBUTION_HEADER,
"Enchantments will have no effect and won't appear in the world."
);
public static final ConfigValue<DistributionMode> DISTRIBUTION_MODE = ConfigValue.create("Enchantments.Distribution.Mode",
DistributionMode.class, DistributionMode.VANILLA,
"Sets in a which way new enchantments will be distributed to the worlds.",
"Allowed values: " + StringUtil.inlineEnum(DistributionMode.class, ", "),
"=".repeat(15) + " ! WARNING ! " + "=".repeat(15),
"You MUST REBOOT your server when changing this. Otherwise result is unpredictable.",
VANILLA_DISTRIBUTION_HEADER,
"[+] Very simple to use, almost no need to configure anything.",
"[+] Handled by the server, automatically supports all possible ways to get enchantments.",
"[+] Very accurate generation, repsects all vanilla game mechanics.",
"[-] Customization is almost non-existent.",
CUSTOM_DISTRIBUTION_HEADER,
"[+] Very flexible and customizable.",
"[+] Possibility for new ways to generate / obtain enchantments.",
"[-] Might be difficult to configure and balance everything.",
"[-] Enchantment generation is not such accurate as vanilla does."
);
public static final ConfigValue<Boolean> DISTRIBUTION_SINGLE_ENCHANT_IN_VILLAGER_BOOKS = ConfigValue.create("Enchantments.Distribution.Custom.Single_Enchant_In_Villager_Books",
true,
"When enabled, enchanted books in villager trades will have no more than 1 enchantment (vanilla or custom one).");
private static final ConfigValue<Map<DistributionWay, DistributionWaySettings>> DISTRIBUTION_WAY_SETTINGS = ConfigValue.forMap("Enchantments.Distribution.Custom.Ways",
id -> StringUtil.getEnum(id, DistributionWay.class).orElse(null),
(cfg, path, def) -> DistributionWaySettings.read(cfg, path + "." + def),
(cfg, path, map) -> map.forEach((type, settings) -> settings.write(cfg, path + "." + type.name())),
() -> Map.of(
DistributionWay.ENCHANTING, new DistributionWaySettings(true, 5, 75, UniInt.of(0, 2)),
DistributionWay.FISHING, new DistributionWaySettings(true, 4, 45, UniInt.of(0, 2)),
DistributionWay.LOOT_GENERATION, new DistributionWaySettings(true, 4, 80, UniInt.of(0, 2)),
DistributionWay.MOB_EQUIPMENT, new DistributionWaySettings(true, 4, 35, UniInt.of(0, 2)),
DistributionWay.VILLAGER, new DistributionWaySettings(true, 4, 60, UniInt.of(0, 2))
),
"Settings for the different ways of obtaining enchantments."
);
public static final ConfigValue<Integer> ENCHANTMENTS_DISPLAY_MODE = ConfigValue.create("Enchantments.Display.Mode",
1,
"Sets how enchantment names and descriptions will be handled on items.",
"=".repeat(15) + " AVAILABLE VALUES " + "=".repeat(15),
"1 = Plain modification of item's lore (lore changes are real and persistent).",
"2 = Packet modification of item's lore (no real changes are made to the items). Requires " + HookId.PROTOCOL_LIB + " to be installed.",
"",
"Plain mode is faster, but may not reflect all changes immediately.",
"Packet mode is slower, but instantly reflect all changes. In creative mode, there is a chance for lore duplication."
);
public static final ConfigValue<Boolean> ENCHANTMENTS_DISPLAY_NAME_HIDE_1ST_LEVEL = ConfigValue.create("Enchantments.Display.Name.Hide_1st_Level",
true,
"Hides enchantment level component from name format for level 1 enchantments.");
public static final ConfigValue<Map<Rarity, String>> ENCHANTMENTS_DISPLAY_NAME_RARITY_FORMAT = ConfigValue.forMap("Enchantments.Display.Name.Rarity",
(id) -> StringUtil.getEnum(id, Rarity.class).orElse(null),
(cfg, path, id) -> cfg.getString(path + "." + id, GENERIC_NAME),
(cfg, path, map) -> map.forEach((rarity, format) -> cfg.set(path + "." + rarity.name(), format)),
() -> Map.of(
Rarity.COMMON, WHITE.enclose(GENERIC_NAME),
Rarity.UNCOMMON, LIGHT_GREEN.enclose(GENERIC_NAME),
Rarity.RARE, LIGHT_CYAN.enclose(GENERIC_NAME),
Rarity.VERY_RARE, LIGHT_ORANGE.enclose(GENERIC_NAME)
),
"Sets enchantment name format depends on enchantment rarity.");
public static final ConfigValue<String> ENCHANTMENTS_DISPLAY_NAME_CURSE_FORMAT = ConfigValue.create("Enchantments.Display.Name.Curse",
LIGHT_RED.enclose(GENERIC_NAME),
"Sets cursed enchantments name format.");
public static final ConfigValue<String> ENCHANTMENTS_DISPLAY_NAME_FORMAT = ConfigValue.create("Enchantments.Display.Name.Format",
ENCHANTMENT_NAME + ENCHANTMENT_LEVEL + ENCHANTMENT_CHARGES,
"Enchantment name format created from name components.");
public static final ConfigValue<String> ENCHANTMENTS_DISPLAY_NAME_COMPONENT_NAME = ConfigValue.create("Enchantments.Display.Name.Component.Name",
GENERIC_VALUE,
"Enchantment name display component for name format.");
public static final ConfigValue<String> ENCHANTMENTS_DISPLAY_NAME_COMPONENT_LEVEL = ConfigValue.create("Enchantments.Display.Name.Component.Level",
" " + GENERIC_VALUE,
"Enchantment level display component for name format.");
public static final ConfigValue<String> ENCHANTMENTS_DISPLAY_NAME_COMPONENT_CHARGES = ConfigValue.create("Enchantments.Display.Name.Component.Charges",
" " + GENERIC_VALUE,
"Enchantment charges display component for name format.");
public static final ConfigValue<Boolean> ENCHANTMENTS_DISPLAY_DESCRIPTION_ENABLED = ConfigValue.create("Enchantments.Display.Description.Enabled",
true,
"When 'true', adds the enchantment description to item lore under enchantment names.",
"For Display-Mode = 2 description is not shown while you're in Creative gamemode.");
public static final ConfigValue<Boolean> ENCHANTMENTS_DISPLAY_DESCRIPTION_BOOKS_ONLY = ConfigValue.create("Enchantments.Display.Description.Books_Only",
false,
"Sets whether or not only enchanted books will have enchantment descriptions.");
public static final ConfigValue<String> ENCHANTMENTS_DISPLAY_DESCRIPTION_FORMAT = ConfigValue.create("Enchantments.Display.Description.Format",
LIGHT_GRAY.enclose("" + GENERIC_DESCRIPTION),
"Sets enc" +
"hantment description format.");
public static final ConfigValue<Boolean> ENCHANTMENTS_CHARGES_ENABLED = ConfigValue.create("Enchantments.Charges.Enabled",
false,
"Enables Enchantment Charges feature.",
"When enabled in the first time, make sure to check enchantments configs for new 'Charges' section.",
URL_CHRAGES);
public static final ConfigValue<TreeMap<Integer, String>> ENCHANTMENTS_CHARGES_FORMAT = ConfigValue.forTreeMap("Enchantments.Charges.Format",
raw -> NumberUtil.getInteger(raw, 0),
(cfg, path, value) -> cfg.getString(path + "." + value, GENERIC_AMOUNT),
(cfg, path, map) -> map.forEach((perc, str) -> cfg.set(path + "." + perc, str)),
() -> {
TreeMap<Integer, String> map = new TreeMap<>();
map.put(0, "#ff9a9a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
map.put(25, "#ffc39a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
map.put(50, "#f6ff9a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
map.put(75, "#bcff9a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
map.put(0, LIGHT_RED.enclose("(" + GENERIC_AMOUNT + "⚡)"));
map.put(25, LIGHT_ORANGE.enclose("(" + GENERIC_AMOUNT + "⚡)"));
map.put(50, LIGHT_YELLOW.enclose("(" + GENERIC_AMOUNT + "⚡)"));
map.put(75, LIGHT_GREEN.enclose("(" + GENERIC_AMOUNT + "⚡)"));
return map;
},
"Enchantment charges format depends on amount of charges left (in percent).",
"If you don't want to display charges, leave only keys with negative values.",
"Use '" + Placeholders.GENERIC_AMOUNT + "' placeholder for amount of charges.")
.setWriter((cfg, path, map) -> map.forEach((perc, str) -> cfg.set(path + "." + perc, str)));
"Use '" + GENERIC_AMOUNT + "' placeholder for charges amount.");
public static final JOption<Boolean> ENCHANTMENTS_CHARGES_COMPARE_TYPE_ONLY = JOption.create("Enchantments.Charges.Compare_Material_Only", false,
"When enabled, only item material will be checked to determine if item can be used as an enchantment fuel.",
"When disabled (default), it will compare the whole item meta including name, lore, model data etc.");
public static final ConfigValue<Boolean> ENCHANTMENTS_CHARGES_COMPARE_TYPE_ONLY = ConfigValue.create("Enchantments.Charges.Compare_Material_Only",
false,
"When enabled, only item material will be checked to determine if an item can be used as an enchantment fuel.",
"When disabled, it will compare the whole item meta including name, lore, model data etc.",
"[Default is false]");
public static final JOption<ItemStack> ENCHANTMENTS_CHARGES_FUEL_ITEM = JOption.create("Enchantments.Charges.Fuel_Item",
public static final ConfigValue<ItemStack> ENCHANTMENTS_CHARGES_FUEL_ITEM = ConfigValue.create("Enchantments.Charges.Fuel_Item",
new ItemStack(Material.LAPIS_LAZULI),
"Default item used to recharge item's enchantments on anvils.",
"If you want different item for certain enchantments, you can do it in that enchantment configs.",
"Item Options: " + Placeholders.URL_ENGINE_SCALER)
.setWriter(JYML::setItem);
public static final JOption<Set<String>> ENCHANTMENTS_DISABLED = JOption.create("Enchantments.Disabled",
Set.of("enchant_name", "other_enchant"),
"A list of enchantments, that will be disabled and removed from the game (server).",
"Enchantment names are the same as enchantment file name in /enchants/ folder. ! Must be in lower_case !",
"Example: To disable 'Explosive Arrows' you need to add 'explosive_arrows' here.")
.mapReader(set -> set.stream().map(String::toLowerCase).collect(Collectors.toSet()));
public static final JOption<Map<String, Set<String>>> ENCHANTMENTS_DISABLED_IN_WORLDS = new JOption<Map<String, Set<String>>>("Enchantments.Disabled_In_Worlds",
(cfg, path, def) -> cfg.getSection(path).stream().collect(Collectors.toMap(k -> k, worldName -> cfg.getStringSet(path + "." + worldName))),
() -> Map.of("your_world_name", Set.of("enchantment_name", "ice_aspect")),
"Here you can disable certain enchantments in certain worlds.",
"Enchantment names are the same as enchantment file name in /enchants/ folder. ! Must be in lower_case !",
"To disable all enchantments for a world, use '" + Placeholders.WILDCARD + "' instead of enchantment names.")
.setWriter((cfg, path, map) -> map.forEach((world, enchants) -> cfg.set(path + "." + world, enchants)));
public static final JOption<Integer> ENCHANTMENTS_DISPLAY_MODE = JOption.create("Enchantments.Display.Mode",
1,
"Sets how enchantment names and descriptions will be handled on items.",
"1 = Plain modification of item's lore (lore changes are real and persistent).",
"2 = Packet modification of item's lore (no real changes are made to the items). Requires ProtocolLib.",
"Plain mode is faster, but may not reflect all changes immediately.",
"Packet mode is slower, but instantly reflect all changes. In creative mode, there is a chance for lore duplication.");
public static final JOption<Boolean> ENCHANTMENTS_DESCRIPTION_ENABLED = JOption.create("Enchantments.Description.Enabled", true,
"When 'true', adds the enchantment description to item lore under enchantment names.",
"For Display-Mode = 2 description is not shown while you're in Creative gamemode.");
public static final JOption<Boolean> ENCHANTMENTS_DESCRIPTION_BOOKS_ONLY = JOption.create("Enchantments.Description.Books_Only",
false,
"Sets whether or not only enchanted books will have enchantment descriptions.");
public static final JOption<String> ENCHANTMENTS_DESCRIPTION_FORMAT = JOption.create("Enchantments.Description.Format",
"&8▸ " + Placeholders.GENERIC_DESCRIPTION,
"Sets the global enchantment description format.").mapReader(Colorizer::apply);
public static final JOption<Integer> ENCHANTMENTS_ITEM_CUSTOM_MAX = JOption.create("Enchantments.Item.Max_Custom_Enchants", 3,
"How many of custom enchantments the item can contain at the same time?");
public static final JOption<Boolean> ENCHANTMENTS_ITEM_SWORD_ENCHANTS_TO_AXES = JOption.create("Enchantments.Item.Sword_Enchants_To_Axes", true,
"Set this to 'true' to allow Sword enchantments for Axes.");
public static final JOption<Boolean> ENCHANTMENTS_ITEM_BOW_ENCHANTS_TO_CROSSBOW = JOption.create("Enchantments.Item.Bow_Enchants_To_Crossbows", true,
"Set this to 'true' to allow Bow enchantments for Crossbows.");
public static final JOption<Boolean> ENCHANTMENTS_ITEM_CHESTPLATE_ENCHANTS_TO_ELYTRA = JOption.create("Enchantments.Item.Chestplate_Enchants_To_Elytra", false,
"Set this to 'true' to allow Chestplate enchantments for Elytras.");
public static final JOption<Boolean> ENCHANTMENTS_ENTITY_PASSIVE_FOR_MOBS = JOption.create("Enchantments.Entity.Apply_Passive_Enchants_To_Mobs", true,
"When enabled, passive enchantments (permanent potion effects, regeneration, etc.) will be applied to mobs as well.",
"Disable this if you're experiencing performance issues.");
public static final JOption<Boolean> ENCHANTMENTS_SINGLE_ENCHANT_IN_VILLAGER_BOOKS = JOption.create("Enchantments.Single_Enchant_In_Villager_Books", true,
"Sets whether or not enchanted books in villager trades will have only 1 enchant, vanilla or custom one.");
private static final JOption<Map<ObtainType, ObtainSettings>> OBTAIN_SETTINGS = new JOption<Map<ObtainType, ObtainSettings>>("Enchantments.Obtaining",
(cfg, path, def) -> Stream.of(ObtainType.values()).collect(Collectors.toMap(k -> k, v -> ObtainSettings.read(cfg, path + "." + v.getPathName()))),
() -> Stream.of(ObtainType.values()).collect(Collectors.toMap(k -> k, v -> new ObtainSettings(true, 4, 80D, 0, 2))),
"Settings for the different ways of obtaining enchantments.")
.setWriter((cfg, path, map) -> map.forEach((type, settings) -> ObtainSettings.write(cfg, path + "." + type.getPathName(), settings)));
"Item Options: " + WIKI_ITEMS_URL);
@NotNull
public static Optional<ObtainSettings> getObtainSettings(@NotNull ObtainType obtainType) {
ObtainSettings settings = OBTAIN_SETTINGS.get().get(obtainType);
public static Optional<DistributionWaySettings> getDistributionWaySettings(@NotNull DistributionWay way) {
DistributionWaySettings settings = DISTRIBUTION_WAY_SETTINGS.get().get(way);
return settings == null || !settings.isEnabled() ? Optional.empty() : Optional.of(settings);
}
@NotNull
public static List<Tier> getDefaultTiers() {
List<Tier> list = new ArrayList<>();
list.add(new Tier("common", 1, "Common", Colors2.WHITE, getObtainWeight(50D)));
list.add(new Tier("rare", 2, "Rare", Colors2.GREEN, getObtainWeight(25D)));
list.add(new Tier("unique", 3, "Unique", Colors2.YELLOW, getObtainWeight(15D)));
list.add(new Tier("legendary", 4, "Legendary", Colors2.ORANGE, getObtainWeight(5D)));
return list;
public static void loadRarityWeights(@NotNull FileConfig config) {
for (Rarity rarity : Rarity.values()) {
int weight = ConfigValue.create("Enchantments.Distribution.Custom.Rarity_Weights." + rarity.name(), rarity.getWeight()).read(config);
rarity.setWeight(weight);
}
}
@NotNull
private static Map<ObtainType, Double> getObtainWeight(double weight) {
Map<ObtainType, Double> map = new HashMap<>();
for (ObtainType obtainType : ObtainType.values()) {
map.put(obtainType, weight);
}
return map;
public static boolean isVanillaDistribution() {
return Config.DISTRIBUTION_MODE.get() == DistributionMode.VANILLA;
}
public static boolean isCustomDistribution() {
return Config.DISTRIBUTION_MODE.get() == DistributionMode.CUSTOM;
}
}

View File

@ -0,0 +1,60 @@
package su.nightexpress.excellentenchants.config;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniInt;
public class DistributionWaySettings {
private final boolean enabled;
private final int maxEnchantments;
private final double generationChance;
private final UniInt amount;
public DistributionWaySettings(boolean enabled,
int maxEnchantments, double generationChance,
@NotNull UniInt amount) {
this.enabled = enabled;
this.maxEnchantments = maxEnchantments;
this.generationChance = generationChance;
this.amount = amount;
}
@NotNull
public static DistributionWaySettings read(@NotNull FileConfig cfg, @NotNull String path) {
boolean enabled = cfg.getBoolean(path + ".Enabled");
int maxEnchantments = cfg.getInt(path + ".Max_Enchantments", 4);
double generationChance = cfg.getDouble(path + ".Generation_Chance", 50D);
UniInt amount = UniInt.read(cfg, path + ".Amount");
return new DistributionWaySettings(enabled, maxEnchantments, generationChance, amount);
}
public void write(@NotNull FileConfig cfg, @NotNull String path) {
cfg.set(path + ".Enabled", this.isEnabled());
cfg.set(path + ".Max_Enchantments", this.getMaxEnchantments());
cfg.set(path + ".Generation_Chance", this.getGenerationChance());
this.amount.write(cfg, path + ".Amount");
}
public int rollAmount() {
return this.amount.roll();
}
public boolean isEnabled() {
return enabled;
}
public int getMaxEnchantments() {
return maxEnchantments;
}
public double getGenerationChance() {
return generationChance;
}
@NotNull
public UniInt getAmount() {
return amount;
}
}

View File

@ -0,0 +1,20 @@
package su.nightexpress.excellentenchants.config;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
public class Keys {
public static NamespacedKey loreSize;
public static NamespacedKey itemRecharged;
public static NamespacedKey entitySpawnReason;
public static void loadKeys(@NotNull ExcellentEnchantsPlugin plugin) {
loreSize = new NamespacedKey(plugin, "lore_size");
itemRecharged = new NamespacedKey(plugin, "item.recharged");
entitySpawnReason = new NamespacedKey(plugin, "entity.spawn_reason");
}
}

View File

@ -1,30 +1,54 @@
package su.nightexpress.excellentenchants.config;
import su.nexmedia.engine.api.lang.LangKey;
import su.nexmedia.engine.lang.EngineLang;
import su.nightexpress.nightcore.core.CoreLang;
import su.nightexpress.nightcore.language.entry.LangString;
import su.nightexpress.nightcore.language.entry.LangText;
import static su.nexmedia.engine.utils.Colors2.*;
import static su.nightexpress.excellentenchants.Placeholders.*;
import static su.nightexpress.nightcore.util.text.tag.Tags.*;
public class Lang extends EngineLang {
public class Lang extends CoreLang {
public static final LangKey COMMAND_LIST_DESC = LangKey.of("Command.List.Desc", "List of all custom enchantments.");
public static final LangString COMMAND_LIST_DESC = LangString.of("Command.List.Desc",
"List of all custom enchantments.");
public static final LangKey COMMAND_ENCHANT_USAGE = LangKey.of("Command.Enchant.Usage", "<enchant> <level> [player] [slot]");
public static final LangKey COMMAND_ENCHANT_DESC = LangKey.of("Command.Enchant.Desc", "Enchants the item in your hand.");
public static final LangKey COMMAND_ENCHANT_DONE_SELF = LangKey.of("Command.Enchant.Done.Self", LIGHT_ORANGE + GENERIC_ITEM + LIGHT_YELLOW + " enchanted with " + GENERIC_ENCHANT + " " + GENERIC_LEVEL + LIGHT_YELLOW + "!");
public static final LangKey COMMAND_ENCHANT_DONE_OTHERS = LangKey.of("Command.Enchant.Done.Others", LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + "'s " + LIGHT_ORANGE + GENERIC_ITEM + LIGHT_YELLOW + " enchanted with " + GENERIC_ENCHANT + " " + GENERIC_LEVEL + LIGHT_YELLOW + "!");
public static final LangKey COMMAND_ENCHANT_ERROR_NO_ITEM = LangKey.of("Command.Enchant.Error.NoItem", RED + "There is no item to enchant!");
public static final LangString COMMAND_ENCHANT_USAGE = LangString.of("Command.Enchant.Usage",
"<enchant> <level> [player] [slot]");
public static final LangKey COMMAND_BOOK_USAGE = LangKey.of("Command.Book.Usage", "<player> <enchant> <level>");
public static final LangKey COMMAND_BOOK_DESC = LangKey.of("Command.Book.Desc", "Gives custom enchanted book.");
public static final LangKey COMMAND_BOOK_DONE = LangKey.of("Command.Book.Done", LIGHT_YELLOW + "Given " + LIGHT_ORANGE + GENERIC_ENCHANT + LIGHT_YELLOW + " enchanted book to " + LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + ".");
public static final LangString COMMAND_ENCHANT_DESC = LangString.of("Command.Enchant.Desc",
"Enchants the item in your hand.");
public static final LangKey COMMAND_TIER_BOOK_USAGE = LangKey.of("Command.TierBook.Usage", "<player> <tier> <level>");
public static final LangKey COMMAND_TIER_BOOK_DESC = LangKey.of("Command.TierBook.Desc", "Gives an enchanted book.");
public static final LangKey COMMAND_TIER_BOOK_ERROR = LangKey.of("Command.TierBook.Error", RED + "Invalid tier!");
public static final LangKey COMMAND_TIER_BOOK_DONE = LangKey.of("Command.TierBook.Done", LIGHT_YELLOW + "Given " + LIGHT_ORANGE + TIER_NAME + LIGHT_YELLOW + " enchanted book to " + LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + ".");
public static final LangText COMMAND_ENCHANT_DONE_SELF = LangText.of("Command.Enchant.Done.Self",
LIGHT_GRAY.enclose(LIGHT_YELLOW.enclose(GENERIC_ITEM) + " enchanted with " + LIGHT_YELLOW.enclose(GENERIC_ENCHANT + " " + GENERIC_LEVEL) + "!"));
public static final LangKey ERROR_NO_ENCHANT = LangKey.of("Error.NoEnchant", RED + "Invalid enchantment.");
public static final LangText COMMAND_ENCHANT_DONE_OTHERS = LangText.of("Command.Enchant.Done.Others",
LIGHT_GRAY.enclose(LIGHT_YELLOW.enclose(PLAYER_DISPLAY_NAME) + "'s " + LIGHT_YELLOW.enclose(GENERIC_ITEM) + " enchanted with " + LIGHT_YELLOW.enclose(GENERIC_ENCHANT + " " + GENERIC_LEVEL) + "!"));
public static final LangText COMMAND_ENCHANT_ERROR_NO_ITEM = LangText.of("Command.Enchant.Error.NoItem",
RED.enclose("There is no item to enchant!"));
public static final LangString COMMAND_BOOK_USAGE = LangString.of("Command.Book.Usage",
"<player> <enchant> <level>");
public static final LangString COMMAND_BOOK_DESC = LangString.of("Command.Book.Desc",
"Gives custom enchanted book.");
public static final LangText COMMAND_BOOK_DONE = LangText.of("Command.Book.Done",
LIGHT_GRAY.enclose("Given " + LIGHT_YELLOW.enclose(GENERIC_ENCHANT) + " enchanted book to " + LIGHT_YELLOW.enclose(PLAYER_DISPLAY_NAME) + "."));
public static final LangString COMMAND_RARITY_BOOK_USAGE = LangString.of("Command.RarityBook.Usage",
"<player> <tier> <level>");
public static final LangString COMMAND_RARITY_BOOK_DESC = LangString.of("Command.RarityBook.Desc",
"Give an enchanted book with enchantment of specified rarity.");
public static final LangText COMMAND_RARITY_BOOK_DONE = LangText.of("Command.RarityBook.Done",
LIGHT_GRAY.enclose("Given " + LIGHT_YELLOW.enclose(GENERIC_NAME) + " enchanted book to " + LIGHT_YELLOW.enclose(PLAYER_DISPLAY_NAME) + "."));
public static final LangText ERROR_NO_ENCHANT = LangText.of("Error.NoEnchant",
RED.enclose("Invalid enchantment."));
public static final LangText ERROR_INVALID_RARITY = LangText.of("Error.InvalidRarity",
RED.enclose("Invalid rarity!"));
}

View File

@ -1,67 +0,0 @@
package su.nightexpress.excellentenchants.config;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
public class ObtainSettings {
private final boolean isEnabled;
private final int enchantsTotalMax;
private final double enchantsCustomGenerationChance;
private final int enchantsCustomMin;
private final int enchantsCustomMax;
public ObtainSettings(boolean isEnabled,
int enchantsTotalMax, double enchantsCustomGenerationChance,
int enchantsCustomMin, int enchantsCustomMax) {
this.isEnabled = isEnabled;
this.enchantsTotalMax = enchantsTotalMax;
this.enchantsCustomGenerationChance = enchantsCustomGenerationChance;
this.enchantsCustomMin = enchantsCustomMin;
this.enchantsCustomMax = enchantsCustomMax;
}
@NotNull
public static ObtainSettings read(@NotNull JYML cfg, @NotNull String path) {
boolean isEnabled = cfg.getBoolean(path + ".Enabled");
int enchantsTotalMax = cfg.getInt(path + ".Enchantments.Total_Maximum", 4);
double enchantsCustomGenerationChance = cfg.getDouble(path + ".Enchantments.Custom_Generation_Chance", 50D);
int enchantsCustomMin = cfg.getInt(path + ".Enchantments.Custom_Minimum", 0);
int enchantsCustomMax = cfg.getInt(path + ".Enchantments.Custom_Maximum", 2);
return new ObtainSettings(isEnabled, enchantsTotalMax, enchantsCustomGenerationChance, enchantsCustomMin, enchantsCustomMax);
}
public static void write(@NotNull JYML cfg, @NotNull String path, @NotNull ObtainSettings settings) {
cfg.set(path + ".Enabled", settings.isEnabled());
cfg.set(path + ".Enchantments.Total_Maximum", settings.getEnchantsTotalMax());
cfg.set(path + ".Enchantments.Custom_Generation_Chance", settings.getEnchantsCustomGenerationChance());
cfg.set(path + ".Enchantments.Custom_Minimum", settings.getEnchantsCustomMin());
cfg.set(path + ".Enchantments.Custom_Maximum", settings.getEnchantsCustomMax());
}
public boolean isEnabled() {
return isEnabled;
}
public int getEnchantsTotalMax() {
return enchantsTotalMax;
}
public double getEnchantsCustomGenerationChance() {
return enchantsCustomGenerationChance;
}
public int getEnchantsCustomMin() {
return enchantsCustomMin;
}
public int getEnchantsCustomMax() {
return enchantsCustomMax;
}
@Override
public String toString() {
return "ObtainSettings{" + "enchantsTotalMax=" + enchantsTotalMax + ", enchantsCustomGenerationChance=" + enchantsCustomGenerationChance + ", enchantsCustomMin=" + enchantsCustomMin + ", enchantsCustomMax=" + enchantsCustomMax + '}';
}
}

View File

@ -1,63 +1,123 @@
/*
* Decompiled with CFR 0.151.
*
* Could not load the following classes:
* org.jetbrains.annotations.NotNull
* su.nexmedia.engine.NexPlugin
* su.nexmedia.engine.api.manager.AbstractManager
* su.nexmedia.engine.api.manager.EventListener
*/
package su.nightexpress.excellentenchants.enchantment;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.manager.AbstractManager;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.impl.armor.FlameWalkerEnchant;
import su.nightexpress.excellentenchants.enchantment.listener.EnchantAnvilListener;
import su.nightexpress.excellentenchants.enchantment.listener.EnchantGenericListener;
import su.nightexpress.excellentenchants.enchantment.listener.EnchantPopulationListener;
import su.nightexpress.excellentenchants.enchantment.menu.EnchantmentsListMenu;
import su.nightexpress.excellentenchants.enchantment.task.ArrowTrailsTask;
import su.nightexpress.excellentenchants.enchantment.task.PassiveEnchantsTask;
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.manager.AbstractManager;
import su.nightexpress.nightcore.util.Pair;
public class EnchantManager
extends AbstractManager<ExcellentEnchants> {
import java.util.*;
public class EnchantManager extends AbstractManager<ExcellentEnchantsPlugin> {
private final Set<Pair<PassiveEnchant, EnchantmentData>> passiveEnchants;
public static final String DIR_ENCHANTS = "/enchants/";
private EnchantmentsListMenu enchantmentsListMenu;
private ArrowTrailsTask arrowTrailsTask;
private PassiveEnchantsTask passiveEnchantsTask;
public EnchantManager(@NotNull ExcellentEnchants plugin) {
public EnchantManager(@NotNull ExcellentEnchantsPlugin plugin) {
super(plugin);
this.passiveEnchants = new HashSet<>();
EnchantRegistry.getEnchantments(PassiveEnchant.class).forEach(passiveEnchant -> {
EnchantmentData enchantmentData = EnchantRegistry.getById(passiveEnchant.getId());
if (enchantmentData == null) return;
this.passiveEnchants.add(Pair.of(passiveEnchant, enchantmentData));
});
}
protected void onLoad() {
this.enchantmentsListMenu = new EnchantmentsListMenu(this.plugin);
this.addListener(new EnchantGenericListener(this));
this.addListener(new EnchantGenericListener(this.plugin, this));
this.addListener(new EnchantAnvilListener(this.plugin));
this.arrowTrailsTask = new ArrowTrailsTask(this.plugin);
this.arrowTrailsTask.start();
this.passiveEnchantsTask = new PassiveEnchantsTask(this.plugin);
this.passiveEnchantsTask.start();
if (Config.isCustomDistribution()) {
this.plugin.info("Using custom distribution system...");
this.addListener(new EnchantPopulationListener(this.plugin));
}
this.addTask(this.plugin.createAsyncTask(this::displayProjectileTrails).setTicksInterval(Config.CORE_PROJECTILE_PARTICLE_INTERVAL.get()));
this.addTask(this.plugin.createTask(this::updatePassiveEnchantEffects).setTicksInterval(Config.CORE_PASSIVE_ENCHANTS_TRIGGER_INTERVAL.get()));
if (EnchantRegistry.isRegistered(FlameWalkerEnchant.ID)) {
this.addTask(this.plugin.createTask(FlameWalkerEnchant::tickBlocks).setSecondsInterval(1));
}
}
protected void onShutdown() {
if (this.enchantmentsListMenu != null) {
this.enchantmentsListMenu.clear();
this.enchantmentsListMenu = null;
}
if (this.arrowTrailsTask != null) {
this.arrowTrailsTask.stop();
this.arrowTrailsTask = null;
}
if (this.passiveEnchantsTask != null) {
this.passiveEnchantsTask.stop();
this.passiveEnchantsTask = null;
if (this.enchantmentsListMenu != null) this.enchantmentsListMenu.clear();
if (EnchantRegistry.isRegistered(FlameWalkerEnchant.ID)) {
FlameWalkerEnchant.clear();
}
}
@NotNull
public EnchantmentsListMenu getEnchantsListGUI() {
return this.enchantmentsListMenu;
public EnchantmentsListMenu getEnchantmentsListMenu() {
return enchantmentsListMenu;
}
public void openEnchantsMenu(@NotNull Player player) {
this.enchantmentsListMenu.open(player);
}
private void displayProjectileTrails() {
EnchantUtils.getEnchantedProjectiles().removeIf(enchantedProjectile -> {
if (!enchantedProjectile.isValid()) {
return true;
}
enchantedProjectile.playParticles();
return false;
});
}
private void updatePassiveEnchantEffects() {
if (this.passiveEnchants.isEmpty()) return;
Set<LivingEntity> entities = this.getPassiveEnchantEntities();
this.passiveEnchants.forEach(pair -> {
PassiveEnchant enchant = pair.getFirst();
EnchantmentData enchantmentData = pair.getSecond();
if (!enchant.isTriggerTime()) return;
for (LivingEntity entity : entities) {
EnchantUtils.getEquipped(entity, enchantmentData).forEach((item, level) -> {
if (!enchant.isAvailableToUse(entity)) return;
if (enchant.isOutOfCharges(item)) return;
if (enchant.onTrigger(entity, item, level)) {
enchant.consumeCharges(item, level);
}
});
}
enchant.updateTriggerTime();
});
}
@NotNull
private Set<LivingEntity> getPassiveEnchantEntities() {
Set<LivingEntity> list = new HashSet<>(plugin.getServer().getOnlinePlayers());
if (Config.CORE_PASSIVE_ENCHANTS_FOR_MOBS.get()) {
plugin.getServer().getWorlds().stream().filter(world -> !world.getPlayers().isEmpty()).forEach(world -> {
list.addAll(world.getEntitiesByClass(LivingEntity.class));
});
}
list.removeIf(entity -> entity.isDead() || !entity.isValid());
return list;
}
}

View File

@ -6,44 +6,47 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.DistributionWay;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.config.ObtainSettings;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.config.DistributionWaySettings;
import su.nightexpress.excellentenchants.enchantment.data.CustomDistribution;
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.excellentenchants.tier.Tier;
import su.nightexpress.nightcore.util.random.Rnd;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.function.BiFunction;
public class EnchantPopulator {
private final ExcellentEnchants plugin;
private final ObtainType obtainType;
private final ItemStack item;
private final Map<Tier, Set<ExcellentEnchant>> candidates;
private final Map<Enchantment, Integer> population;
//private final ExcellentEnchants plugin;
private final DistributionWay distributionWay;
private final ItemStack item;
private final Map<Rarity, Set<EnchantmentData>> candidates;
private final Map<Enchantment, Integer> defaultPopulation;
private final Set<BiFunction<EnchantmentData, CustomDistribution, Boolean>> predicates;
private World world;
private Function<ExcellentEnchant, Integer> levelGenerator;
private BiFunction<EnchantmentData, CustomDistribution, Integer> levelGenerator;
public EnchantPopulator(@NotNull ExcellentEnchants plugin, @NotNull ItemStack item, @NotNull ObtainType obtainType) {
this.plugin = plugin;
public EnchantPopulator(@NotNull ExcellentEnchantsPlugin plugin, @NotNull ItemStack item, @NotNull DistributionWay distributionWay) {
//this.plugin = plugin;
this.item = item;
this.obtainType = obtainType;
this.distributionWay = distributionWay;
this.candidates = new HashMap<>();
this.population = new HashMap<>();
this.withLevelGenerator(enchant -> enchant.generateLevel(this.getObtainType()));
this.defaultPopulation = new HashMap<>();
this.predicates = new HashSet<>();
this.withLevelGenerator((data, distribution) -> distribution.generateLevel(this.getDistributionWay()));
this.fillDefaultCandidates();
//this.fillDefaultCandidates();
}
@NotNull
@ -53,42 +56,61 @@ public class EnchantPopulator {
}
@NotNull
public EnchantPopulator withLevelGenerator(@NotNull Function<ExcellentEnchant, Integer> levelGenerator) {
public EnchantPopulator withLevelGenerator(@NotNull BiFunction<EnchantmentData, CustomDistribution, Integer> levelGenerator) {
this.levelGenerator = levelGenerator;
return this;
}
@NotNull
public EnchantPopulator withCondition(@NotNull BiFunction<EnchantmentData, CustomDistribution, Boolean> predicate) {
this.predicates.add(predicate);
return this;
}
@NotNull
public EnchantPopulator withDefaultPopulation(@NotNull Map<Enchantment, Integer> population) {
this.getPopulation().putAll(population);
this.defaultPopulation.putAll(population);
//this.getPopulation().putAll(population);
return this;
}
private void fillDefaultCandidates() {
this.plugin.getTierManager().getTiers().forEach(tier -> {
Set<ExcellentEnchant> enchants = EnchantRegistry.getOfTier(tier);
for (Rarity rarity : Rarity.values()) {
Set<EnchantmentData> dataSet = EnchantRegistry.getEnchantments(rarity);
enchants.removeIf(enchant -> {
return !enchant.isObtainable(this.getObtainType()) || (!enchant.getBackend().canEnchantItem(this.getItem()) && !EnchantUtils.isBook(this.getItem()));
dataSet.removeIf(data -> {
CustomDistribution distribution = (CustomDistribution) data.getDistributionOptions();
// Check if can be distributed.
if (!distribution.isDistributable(this.getDistributionWay())) return true;
// Check for custom conditions.
if (!this.predicates.isEmpty() && !this.predicates.stream().allMatch(predicate -> predicate.apply(data, distribution))) return true;
// Enchanting books is always good.
if (this.getItem().getType() == Material.BOOK && this.getDistributionWay() == DistributionWay.ENCHANTING) return false;
// Check if item can be enchanted.
return !data.getEnchantment().canEnchantItem(this.getItem()) && !EnchantUtils.isEnchantedBook(this.getItem());
});
this.candidates.put(tier, enchants);
});
this.candidates.put(rarity, dataSet);
}
}
public boolean isEmpty() {
return this.getCandidates().isEmpty() || this.getCandidates().values().stream().allMatch(Set::isEmpty);
}
public boolean isEmpty(@NotNull Tier tier) {
return this.getCandidates(tier).isEmpty();
public boolean isEmpty(@NotNull Rarity rarity) {
return this.getCandidates(rarity).isEmpty();
}
public void purge(@NotNull Tier tier) {
this.getCandidates().remove(tier);
public void purge(@NotNull Rarity rarity) {
this.getCandidates().remove(rarity);
}
public void purge(@NotNull Tier tier, @NotNull ExcellentEnchant enchant) {
public void purge(@NotNull Rarity tier, @NotNull EnchantmentData enchant) {
this.getCandidates(tier).remove(enchant);
this.getCandidates().keySet().removeIf(this::isEmpty);
}
@ -99,8 +121,8 @@ public class EnchantPopulator {
}
@NotNull
public ObtainType getObtainType() {
return obtainType;
public DistributionWay getDistributionWay() {
return distributionWay;
}
@Nullable
@ -109,89 +131,98 @@ public class EnchantPopulator {
}
@NotNull
public Function<ExcellentEnchant, Integer> getLevelGenerator() {
public BiFunction<EnchantmentData, CustomDistribution, Integer> getLevelGenerator() {
return levelGenerator;
}
@NotNull
public Map<Tier, Set<ExcellentEnchant>> getCandidates() {
public Map<Rarity, Set<EnchantmentData>> getCandidates() {
return this.candidates;
}
@NotNull
public Set<ExcellentEnchant> getCandidates(@NotNull Tier tier) {
return this.getCandidates().getOrDefault(tier, new HashSet<>());
}
@NotNull
public Map<Enchantment, Integer> getPopulation() {
return this.population;
public Set<EnchantmentData> getCandidates(@NotNull Rarity rarity) {
return this.candidates.getOrDefault(rarity, new HashSet<>());
}
@Nullable
public Tier getTierByChance() {
Map<Tier, Double> map = this.getCandidates().keySet().stream()
.filter(tier -> tier.getChance(this.getObtainType()) > 0D)
.collect(Collectors.toMap(k -> k, v -> v.getChance(this.getObtainType()), (o, n) -> n, HashMap::new));
if (map.isEmpty()) return null;
public Rarity getRarityByWeight() {
Map<Rarity, Double> map = new HashMap<>();
return Rnd.getByWeight(map);
for (Rarity rarity : this.getCandidates().keySet()) {
map.put(rarity, (double) rarity.getWeight());
}
return map.isEmpty() ? null : Rnd.getByWeight(map);
}
@Nullable
public ExcellentEnchant getEnchantByChance(@NotNull Tier tier) {
Map<ExcellentEnchant, Double> map = this.getCandidates(tier).stream()
.collect(Collectors.toMap(k -> k, v -> v.getObtainChance(this.getObtainType())));
public EnchantmentData getEnchantmentByWeight(@NotNull Rarity rarity) {
Map<EnchantmentData, Double> map = new HashMap<>();
this.getCandidates(rarity).forEach(enchantmentData -> {
CustomDistribution distribution = (CustomDistribution) enchantmentData.getDistributionOptions();
map.put(enchantmentData, distribution.getWeight(this.getDistributionWay()));
});
return map.isEmpty() ? null : Rnd.getByWeight(map);
}
@NotNull
public Map<Enchantment, Integer> createPopulation() {
Map<Enchantment, Integer> population = this.getPopulation();
this.candidates.clear();
this.fillDefaultCandidates();
ObtainSettings settings = Config.getObtainSettings(this.getObtainType()).orElse(null);
if (settings == null || !Rnd.chance(settings.getEnchantsCustomGenerationChance())) return population;
Map<Enchantment, Integer> population = new HashMap<>(this.defaultPopulation);
int enchantsLimit = settings.getEnchantsTotalMax();
int enchantsRolled = Rnd.get(settings.getEnchantsCustomMin(), settings.getEnchantsCustomMax());
DistributionWaySettings settings = Config.getDistributionWaySettings(this.getDistributionWay()).orElse(null);
if (settings == null || !Rnd.chance(settings.getGenerationChance())) return population;
int enchantsLimit = settings.getMaxEnchantments();
int enchantsRolled = settings.rollAmount();
// Try to populate as many as possible.
while (!this.isEmpty() && enchantsRolled > 0) {
// Limit reached.
if (population.size() >= enchantsLimit) break;
Tier tier = this.getTierByChance();
if (tier == null) break; // no tiers left.
Rarity rarity = this.getRarityByWeight();
if (rarity == null) break; // no tiers left.
ExcellentEnchant enchant = this.getEnchantByChance(tier);
// Remove entire tier if no enchants can be selected.
if (enchant == null) {
this.purge(tier);
EnchantmentData enchantmentData = this.getEnchantmentByWeight(rarity);
// Remove entire rarity if no enchants can be selected.
if (enchantmentData == null) {
this.purge(rarity);
continue;
}
if (!(enchantmentData.getDistributionOptions() instanceof CustomDistribution distribution)) {
this.purge(rarity, enchantmentData);
continue;
}
// Remove disabled world enchants.
if (world != null && enchant.isDisabledInWorld(world)) {
this.purge(tier, enchant);
if (this.world != null && !enchantmentData.isAvailableToUse(this.world)) {
this.purge(rarity, enchantmentData);
continue;
}
// Remove conflicting enchants.
if (population.keySet().stream().anyMatch(has -> has.conflictsWith(enchant.getBackend()) || enchant.getBackend().conflictsWith(has))) {
this.purge(tier, enchant);
if (population.keySet().stream().anyMatch(has -> has.conflictsWith(enchantmentData.getEnchantment()) || enchantmentData.getEnchantment().conflictsWith(has))) {
this.purge(rarity, enchantmentData);
continue;
}
// Level generation failed.
int level = this.getLevelGenerator().apply(enchant);
if (level < enchant.getStartLevel()) {
this.purge(tier, enchant);
int level = this.getLevelGenerator().apply(enchantmentData, distribution);
if (level < enchantmentData.getMinLevel()) {
this.purge(rarity, enchantmentData);
continue;
}
// All good!
this.purge(tier, enchant);
population.put(enchant.getBackend(), level);
this.purge(rarity, enchantmentData);
population.put(enchantmentData.getEnchantment(), level);
enchantsRolled--;
}
@ -201,16 +232,15 @@ public class EnchantPopulator {
public boolean populate() {
ItemStack item = this.getItem();
AtomicBoolean status = new AtomicBoolean(false);
Map<Enchantment, Integer> population = this.createPopulation();//this.getPopulation().isEmpty() ? this.createPopulation() : this.getPopulation();
var population = this.getPopulation().isEmpty() ? this.createPopulation() : this.getPopulation();
boolean singleVillagerBook = this.getObtainType() == ObtainType.VILLAGER
&& item.getType() == Material.ENCHANTED_BOOK
&& Config.ENCHANTMENTS_SINGLE_ENCHANT_IN_VILLAGER_BOOKS.get();
boolean singleVillagerBook = this.getDistributionWay() == DistributionWay.VILLAGER
&& EnchantUtils.isEnchantedBook(item)
&& Config.DISTRIBUTION_SINGLE_ENCHANT_IN_VILLAGER_BOOKS.get();
if (singleVillagerBook) {
if (!population.isEmpty()) {
EnchantUtils.getAll(item).keySet().forEach(enchantment -> EnchantUtils.remove(item, enchantment));
EnchantUtils.removeAll(item);
}
while (population.size() > 1) {
population.remove(Rnd.get(population.keySet()));

View File

@ -1,361 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.config;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.Colorizer;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.ExcellentEnchantsAPI;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
import su.nightexpress.excellentenchants.tier.Tier;
import su.nightexpress.excellentenchants.tier.TierManager;
import java.util.*;
public class EnchantDefaults {
private final Map<ObtainType, Double> obtainChance;
private final Map<ObtainType, int[]> obtainLevelCap;
private String displayName;
private Tier tier;
private List<String> description;
private boolean hiddenFromList;
private boolean isTreasure;
private boolean tradeable;
private boolean discoverable;
private int levelMin;
private int levelMax;
private int maxMergeLevel;
private EnchantScaler levelByEnchantCost;
private EnchantScaler anvilMergeCost;
private Set<String> conflicts;
private boolean visualEffects;
private boolean chargesEnabled;
private boolean chargesCustomFuel;
private EnchantScaler chargesMax;
private EnchantScaler chargesConsumeAmount;
private EnchantScaler chargesRechargeAmount;
private ItemStack chargesFuel;
public EnchantDefaults(@NotNull ExcellentEnchant enchant) {
this.setDisplayName(StringUtil.capitalizeUnderscored(enchant.getId()));
this.setTier(0.1);
this.setDescription(new ArrayList<>());
this.setHiddenFromList(false);
this.setTreasure(false);
this.setTradeable(true);
this.setDiscoverable(true);
this.setLevelMin(1);
this.setLevelMax(3);
this.setMaxMergeLevel(-1);
this.setConflicts(new HashSet<>());
this.setVisualEffects(true);
this.obtainChance = new HashMap<>();
this.obtainLevelCap = new HashMap<>();
}
public void load(@NotNull ExcellentEnchant enchant) {
ExcellentEnchants plugin = ExcellentEnchantsAPI.PLUGIN;
JYML cfg = enchant.getConfig();
this.setDisplayName(JOption.create("Name", this.getDisplayName(),
"Enchantment display name. It will be shown in item lore.").read(cfg));
Tier tier = plugin.getTierManager().getTierById(JOption.create("Tier", this.getTier().getId(),
"Enchantment tier. Must be a valid tier identifier from the '" + TierManager.FILE_NAME + "'.").read(cfg));
this.setTier(tier == null ? plugin.getTierManager().getMostCommon() : tier);
//this.getTier().getEnchants().add(enchant);
this.setDescription(JOption.create("Description", this.getDescription(),
"Enchantment description. It will be shown in item lore under enchantment name.",
"You can use 'Enchantment' placeholders: " + Placeholders.URL_PLACEHOLDERS)
.read(cfg));
this.setHiddenFromList(JOption.create("Hide_From_List", false,
"Sets whether or not this enchantment will be hidden from Enchants GUI.").read(cfg));
this.setTreasure(JOption.create("Is_Treasure", this.isTreasure(),
"Sets whether this enchantment is a treasure enchantment.",
"Treasure enchantments can only be received via looting, trading, or fishing.").read(cfg));
if (Config.ENCHANTMENTS_INTERNAL_HANDLER.get()) {
this.setTradeable(JOption.create("Tradeable", this.isTradeable(),
"Sets whether or not this enchantment can be populated in villager trades.").read(cfg));
this.setDiscoverable(JOption.create("Discoverable", this.isTradeable(),
"Sets whether or not this enchantment can be populated in enchanting table.").read(cfg));
}
else {
this.setTradeable(false);
this.setDiscoverable(false);
}
this.setLevelMin(JOption.create("Level.Min", this.getLevelMin(),
"Sets the minimal (start) enchantment level. Can not be less than 1.").read(cfg));
this.setLevelMax(JOption.create("Level.Max", this.getLevelMax(),
"Sets the maximal enchantment level. Can not be less than min. level.",
"Note: While you can 'bypass' this value by enchant commands, all level-dependant enchantment",
"settings will have a limit up to this setting.").read(cfg));
this.setMaxMergeLevel(JOption.create("Anvil.Max_Merge_Level", this.getMaxMergeLevel(),
"Sets max. enchantment level that can be obtained by combining 2 items with this enchantment.",
"Set this to '-1' to remove merge limit and just use 'Max Level' instead."
).read(cfg));
this.setLevelByEnchantCost(EnchantScaler.read(enchant, ObtainType.ENCHANTING.getPathName() + ".Level_By_Exp_Cost",
(int)(30D / this.levelMax) + " * " + Placeholders.ENCHANTMENT_LEVEL,
"Sets how much XP levels must be used in enchanting table to obtain this enchantment.",
"With a default formula '9 * %enchantment_level%' it will be [9, 18, 27] XP levels for [1, 2, 3] enchantment levels."));
this.setAnvilMergeCost(EnchantScaler.read(enchant, "Anvil.Merge_Cost", Placeholders.ENCHANTMENT_LEVEL,
"Sets how much XP levels will be added to the anvil cost when combining custom enchantments."));
for (ObtainType obtainType : ObtainType.values()) {
double obtainChance = JOption.create(obtainType.getPathName() + ".Chance", 50D,
"Chance for this enchantment to be obtained via " + obtainType.getPathName()).read(cfg);
this.getObtainChance().put(obtainType, obtainChance);
int levelMin = JOption.create(obtainType.getPathName() + ".Level.Min", -1,
"Minimal level when obtained via " + obtainType.getPathName(),
"Can not be less than enchantment min. level. Set -1 to use enchantment min. level.").read(cfg);
int levelMax = JOption.create(obtainType.getPathName() + ".Level.Max", -1,
"Maximal level when obtained via " + obtainType.getPathName(),
"Can not be greater than enchantment max. level. Set -1 to use enchantment max. level.").read(cfg);
this.getObtainLevelCap().put(obtainType, new int[]{levelMin, levelMax});
}
this.setConflicts(JOption.create("Conflicts", this.getConflicts(),
"A list of conflicting enchantment names.",
"Conflicting enchantments can not be combined on anvils and obtained together on the same item.").read(cfg));
this.setVisualEffects(JOption.create("Settings.Visual_Effects", this.isVisualEffects(),
"Enables/Disables enchantment visual effects, such as particles.").read(cfg));
if (Config.ENCHANTMENTS_CHARGES_ENABLED.get()) {
this.setChargesEnabled(JOption.create("Settings.Charges.Enabled", this.isChargesEnabled(),
"When 'true' enables the Charges system for this enchantment.",
"When enchanted the first time on enchanting table, it will have maximum charges amount.").read(cfg));
this.setChargesCustomFuel(JOption.create("Settings.Charges.Custom_Fuel", this.isChargesCustomFuel(),
"When 'true' uses different (non-default) fuel item (from the 'Fuel_Item' setting) to recharge.").read(cfg));
this.setChargesMax(EnchantScaler.read(enchant, "Settings.Charges.Maximum", "100",
"Maximum amount of charges for the enchantment."));
this.setChargesConsumeAmount(EnchantScaler.read(enchant, "Settings.Charges.Consume_Amount", "1",
"How many charges will be consumed when enchantment is triggered?"));
this.setChargesRechargeAmount(EnchantScaler.read(enchant, "Settings.Charges.Recharge_Amount", "25",
"How many charges will be restored when using 'Fuel Item' in anvil?"));
this.setChargesFuel(JOption.create("Settings.Charges.Fuel_Item", new ItemStack(Material.LAPIS_LAZULI),
"An item, that will be used to restore enchantment charges on anvils.",
"Item Options:" + Placeholders.URL_ENGINE_ITEMS)
.setWriter(JYML::setItem).read(cfg));
}
}
@NotNull
public String getDisplayName() {
return displayName;
}
public void setDisplayName(@NotNull String displayName) {
this.displayName = Colorizer.apply(displayName);
}
@NotNull
public Tier getTier() {
return tier;
}
public void setTier(double rarity) {
this.setTier(ExcellentEnchantsAPI.getTierManager().getByRarityModifier(rarity));
}
public void setTier(@NotNull Tier tier) {
this.tier = tier;
}
public void setDescription(@NotNull String... description) {
this.setDescription(Arrays.asList(description));
}
public void setDescription(@NotNull List<String> description) {
this.description = Colorizer.apply(description);
}
@NotNull
public List<String> getDescription() {
return description;
}
public boolean isHiddenFromList() {
return hiddenFromList;
}
public void setHiddenFromList(boolean hiddenFromList) {
this.hiddenFromList = hiddenFromList;
}
public boolean isTreasure() {
return isTreasure;
}
public void setTreasure(boolean treasure) {
isTreasure = treasure;
}
public boolean isTradeable() {
return tradeable;
}
public void setTradeable(boolean tradeable) {
this.tradeable = tradeable;
}
public boolean isDiscoverable() {
return discoverable;
}
public void setDiscoverable(boolean discoverable) {
this.discoverable = discoverable;
}
public void setLevelMin(int levelMin) {
this.levelMin = Math.max(1, levelMin);
}
public int getLevelMin() {
return levelMin;
}
public void setLevelMax(int levelMax) {
this.levelMax = Math.max(1, levelMax);
}
public int getLevelMax() {
return levelMax;
}
public int getMaxMergeLevel() {
return this.maxMergeLevel;
}
public void setMaxMergeLevel(int maxMergeLevel) {
this.maxMergeLevel = Math.min(this.getLevelMax(), maxMergeLevel);
}
@NotNull
public EnchantScaler getLevelByEnchantCost() {
return levelByEnchantCost;
}
public void setLevelByEnchantCost(@NotNull EnchantScaler levelByEnchantCost) {
this.levelByEnchantCost = levelByEnchantCost;
}
@NotNull
public EnchantScaler getAnvilMergeCost() {
return anvilMergeCost;
}
public void setAnvilMergeCost(@NotNull EnchantScaler anvilMergeCost) {
this.anvilMergeCost = anvilMergeCost;
}
@NotNull
public Map<ObtainType, Double> getObtainChance() {
return obtainChance;
}
@NotNull
public Map<ObtainType, int[]> getObtainLevelCap() {
return obtainLevelCap;
}
public void setConflicts(@NotNull String... conflicts) {
this.setConflicts(new HashSet<>(Arrays.asList(conflicts)));
}
public void setConflicts(@NotNull Set<String> conflicts) {
this.conflicts = conflicts;
}
@NotNull
public Set<String> getConflicts() {
return conflicts;
}
public boolean isVisualEffects() {
return visualEffects;
}
public void setVisualEffects(boolean visualEffects) {
this.visualEffects = visualEffects;
}
public boolean isChargesEnabled() {
return chargesEnabled;
}
public void setChargesEnabled(boolean chargesEnabled) {
this.chargesEnabled = chargesEnabled;
}
public boolean isChargesCustomFuel() {
return chargesCustomFuel;
}
public void setChargesCustomFuel(boolean chargesCustomFuel) {
this.chargesCustomFuel = chargesCustomFuel;
}
@NotNull
public EnchantScaler getChargesMax() {
return chargesMax;
}
public void setChargesMax(@NotNull EnchantScaler chargesMax) {
this.chargesMax = chargesMax;
}
@Nullable
public ItemStack getChargesFuel() {
return chargesFuel;
}
public void setChargesFuel(@Nullable ItemStack chargesFuel) {
this.chargesFuel = chargesFuel;
}
@NotNull
public EnchantScaler getChargesConsumeAmount() {
return chargesConsumeAmount;
}
public void setChargesConsumeAmount(@NotNull EnchantScaler chargesConsumeAmount) {
this.chargesConsumeAmount = chargesConsumeAmount;
}
@NotNull
public EnchantScaler getChargesRechargeAmount() {
return chargesRechargeAmount;
}
public void setChargesRechargeAmount(@NotNull EnchantScaler chargesRechargeAmount) {
this.chargesRechargeAmount = chargesRechargeAmount;
}
}

View File

@ -1,80 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.Evaluator;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import java.util.*;
public class EnchantScaler {
public EnchantScaler(@NotNull ExcellentEnchant enchant, @NotNull String path) {
this(enchant.getConfig(), path, Placeholders.ENCHANTMENT_LEVEL, enchant.getStartLevel(), enchant.getMaxLevel());
}
@NotNull
public static EnchantScaler read(@NotNull ExcellentEnchant enchant, @NotNull String path, @NotNull String def, @Nullable String... comments) {
enchant.getConfig().addMissing(path, def);
if (comments != null) {
List<String> list = new ArrayList<>(Arrays.asList(comments));
list.add("You can use formulas/expressions here: " + Placeholders.URL_ENGINE_SCALER);
list.add("Level placeholder: " + Placeholders.ENCHANTMENT_LEVEL);
enchant.getConfig().setComments(path, list);
}
return new EnchantScaler(enchant, path);
}
private final int levelMin;
private final int levelMax;
private final TreeMap<Integer, Double> values;
public EnchantScaler(@NotNull JYML cfg, @NotNull String path, @NotNull String levelPlaceholder, int levelMin, int levelMax) {
this.levelMin = levelMin;
this.levelMax = levelMax;
this.values = new TreeMap<>();
// Load different values for each object level.
Set<String> lvlKeys = cfg.getSection(path);
if (!lvlKeys.isEmpty()) {
for (String sLvl : lvlKeys) {
int eLvl = StringUtil.getInteger(sLvl, 0);
if (eLvl < this.getLevelMin() || eLvl > this.getLevelMax()) continue;
String formula = cfg.getString(path + "." + sLvl, "0").replace(levelPlaceholder, sLvl);
values.put(eLvl, Evaluator.evaluate(formula));
}
return;
}
// Load the single formula for all object levels.
for (int lvl = this.getLevelMin(); lvl < (this.getLevelMax() + 1); lvl++) {
String sLvl = String.valueOf(lvl);
String exChance = cfg.getString(path, "").replace(levelPlaceholder, sLvl);
if (exChance.isEmpty()) continue;
values.put(lvl, Evaluator.evaluate(exChance));
}
}
public int getLevelMin() {
return this.levelMin;
}
public int getLevelMax() {
return this.levelMax;
}
@NotNull
public TreeMap<Integer, Double> getValues() {
return this.values;
}
public double getValue(int level) {
Map.Entry<Integer, Double> en = this.values.floorEntry(level);
return en != null ? en.getValue() : 0D;
}
}

View File

@ -0,0 +1,738 @@
package su.nightexpress.excellentenchants.enchantment.data;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.DistributionWay;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.distribution.DistributionOptions;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.util.EnchantPlaceholders;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.language.LangAssets;
import su.nightexpress.nightcore.manager.AbstractFileData;
import su.nightexpress.nightcore.manager.SimpeListener;
import su.nightexpress.nightcore.util.ItemUtil;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.PDCUtil;
import su.nightexpress.nightcore.util.StringUtil;
import su.nightexpress.nightcore.util.placeholder.PlaceholderMap;
import su.nightexpress.nightcore.util.random.Rnd;
import java.io.File;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static su.nightexpress.excellentenchants.Placeholders.*;
public abstract class AbstractEnchantmentData extends AbstractFileData<ExcellentEnchantsPlugin> implements EnchantmentData {
protected Enchantment enchantment;
private Rarity rarity;
private String displayName;
private List<String> description;
private boolean hiddenFromList;
private boolean treasure;
private boolean visualEffects;
private int minLevel;
private int maxLevel;
//private int maxMergeLevel;
private Modifier minCost;
private Modifier maxCost;
//private Modifier anvilMergeCost;
private boolean chargesEnabled;
private boolean chargesCustomFuel;
private Modifier chargesMax;
private Modifier chargesConsumeAmount;
private Modifier chargesRechargeAmount;
private ItemStack chargesFuel;
private final DistributionOptions distributionOptions;
private final Set<String> conflicts;
private final NamespacedKey chargesKey;
private final EnchantPlaceholders placeholders;
public AbstractEnchantmentData(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(new ArrayList<>());
this.setRarity(Rarity.COMMON);
this.setStartLevel(1);
this.setMaxLevel(3);
this.conflicts = new HashSet<>();
this.chargesKey = new NamespacedKey(plugin, this.getId() + ".charges");
this.placeholders = new EnchantPlaceholders();
if (!Config.isVanillaDistribution()) {
this.distributionOptions = new CustomDistribution(this);
}
else {
this.distributionOptions = new VanillaDistribution();
}
}
public void registerListeners() {
if (this instanceof SimpeListener listener) {
this.plugin.getPluginManager().registerEvents(listener, plugin);
}
}
@Override
public boolean checkServerRequirements() {
return true;
}
@Override
protected boolean onLoad(@NotNull FileConfig cfg) {
this.setRarity(ConfigValue.create("Settings.Rarity", Rarity.class, this.rarity,
"The rarity is an attribute of an enchantment.",
"It affects the chance of getting an enchantment from enchanting or loots as well as the combination cost in anvil."
).read(cfg));
this.setDisplayName(ConfigValue.create("Settings.Name",
StringUtil.capitalizeUnderscored(this.getId()),
"Enchantment name."
).read(cfg));
this.setDescription(ConfigValue.create("Settings.Description",
this.getDescription(),
"Enchantment description.",
"You can use 'Enchantment' placeholders: " + URL_PLACEHOLDERS
).read(cfg));
this.setStartLevel(ConfigValue.create("Settings.Level.Min",
this.getMinLevel(),
"Min. enchantment level."
).read(cfg));
this.setMaxLevel(ConfigValue.create("Settings.Level.Max",
this.getMaxLevel(),
"Max. enchantment level."
).read(cfg));
this.setHiddenFromList(ConfigValue.create("Settings.Hide_From_List",
false,
"Sets whether or not this enchantment will be hidden from Enchants GUI."
).read(cfg));
this.setConflicts(ConfigValue.create("Settings.Conflicts",
this.getConflicts(),
"Makes this enchantment exclusive for ones in the list.",
"Conflicting enchantments can not be combined on anvils and obtained together on the same item."
).read(cfg));
this.setVisualEffects(ConfigValue.create("Settings.VisualEffects.Enabled",
true,
"Enables enchantment visual effects (mostly particles)."
).read(cfg));
this.setTreasure(ConfigValue.create("Distribution.Treasure",
false,
"Sets whether this enchantment is a treasure enchantment.",
"Treasure enchantments can only be received via looting, trading, or fishing."
).read(cfg));
//int costAdjust = Math.max(7, 42 - this.getMaxLevel() * 7);
double costBase = Config.isVanillaDistribution() ? 45D : 30D;
double costAdjust = costBase / this.getMaxLevel();
this.setMinCost(Modifier.read(cfg, "Distribution." + DistributionWay.ENCHANTING.getPathName() + ".Min_Cost",
Modifier.add(1 - costAdjust, costAdjust, 1),
VANILLA_DISTRIBUTION_HEADER,
"Sets min. **modified** level cost for this enchantment to be selected in enchanting table.",
"Explanation: https://minecraft.wiki/w/Enchanting_mechanics#How_enchantments_are_chosen",
"Vanilla costs: https://minecraft.wiki/w/Enchanting/Levels",
CUSTOM_DISTRIBUTION_HEADER,
"Sets min. **plain** level cost for this enchantment to be selected in enchanting table.")
);
this.setMaxCost(Modifier.read(cfg, "Distribution." + DistributionWay.ENCHANTING.getPathName() + ".Max_Cost",
Modifier.add(12 - costAdjust, costAdjust, 1),
VANILLA_DISTRIBUTION_HEADER,
"Sets max. **modified** level cost for this enchantment to be selected in enchanting table.",
"Explanation: https://minecraft.wiki/w/Enchanting_mechanics#How_enchantments_are_chosen",
"Vanilla costs: https://minecraft.wiki/w/Enchanting/Levels",
CUSTOM_DISTRIBUTION_HEADER,
"Sets max. **plain** level cost for this enchantment to be selected in enchanting table.")
);
this.distributionOptions.load(cfg);
/*this.setAnvilMergeCost(Modifier.read(cfg, "Anvil.Merge.Cost",
Modifier.add(1, 1, 1),
"Sets XP cost to apply or transfer this enchantment using anvils."
));
this.setMaxMergeLevel(ConfigValue.create("Anvil.Merge.Max_Level",
-1,
"Max. enchantment level that can be obtained by combining 2 items with this enchantment.",
"Set to '-1' to remove limit and cap to max. enchantment level."
).read(cfg));*/
if (Config.ENCHANTMENTS_CHARGES_ENABLED.get() && !this.isCurse()) {
this.setChargesEnabled(ConfigValue.create("Charges.Enabled",
false,
"When 'true' enables the Charges system for this enchantment.",
"[*] Enchantments in enchanting table are generated with maximum charges."
).read(cfg));
this.setChargesCustomFuel(ConfigValue.create("Charges.Custom_Fuel",
false,
"When 'true' uses different (non-default) fuel item (from the 'Fuel_Item' setting) to recharge."
).read(cfg));
this.setChargesMax(Modifier.read(cfg, "Charges.Maximum",
Modifier.add(100, 25, 1),
"Maximum amount of charges for the enchantment."
));
this.setChargesConsumeAmount(Modifier.read(cfg, "Charges.Consume_Amount",
Modifier.add(1, 0, 0),
"How many charges will be consumed when enchantment is triggered?"
));
this.setChargesRechargeAmount(Modifier.read(cfg, "Charges.Recharge_Amount",
Modifier.add(25, 5, 1),
"How many charges will be restored when using 'Fuel Item' in anvil?"
));
this.setChargesFuel(ConfigValue.create("Charges.Fuel_Item",
new ItemStack(Material.LAPIS_LAZULI),
"An item, that will be used to restore enchantment charges on anvils.",
WIKI_ITEMS_URL
).read(cfg));
}
this.placeholders
.add(ENCHANTMENT_ID, this::getId)
.add(ENCHANTMENT_NAME, this::getName)
.add(ENCHANTMENT_NAME_FORMATTED, this::getNameFormatted)
.add(ENCHANTMENT_DESCRIPTION, () -> String.join("\n", this.getDescription()))
.add(ENCHANTMENT_DESCRIPTION_FORMATTED, () -> String.join("\n", this.getDescriptionFormatted()))
.add(ENCHANTMENT_DESCRIPTION_REPLACED, level -> String.join("\n", this.getDescriptionReplaced(level)))
.add(ENCHANTMENT_LEVEL, NumberUtil::toRoman)
.add(ENCHANTMENT_LEVEL_MIN, () -> String.valueOf(this.getMinLevel()))
.add(ENCHANTMENT_LEVEL_MAX, () -> String.valueOf(this.getMaxLevel()))
.add(ENCHANTMENT_RARITY, () -> plugin.getLangManager().getEnum(this.getRarity()))
.add(ENCHANTMENT_FIT_ITEM_TYPES, () -> {
if (this.getItemCategories().length == 0) return plugin.getLangManager().getEnum(this.getCategory());
return String.join(", ", Stream.of(this.getItemCategories()).map(type -> plugin.getLangManager().getEnum(type)).toList());
})
.add(ENCHANTMENT_CHARGES_MAX_AMOUNT, level -> NumberUtil.format(this.getChargesMax(level)))
.add(ENCHANTMENT_CHARGES_CONSUME_AMOUNT, level -> NumberUtil.format(this.getChargesConsumeAmount(level)))
.add(ENCHANTMENT_CHARGES_RECHARGE_AMOUNT, level -> NumberUtil.format(this.getChargesRechargeAmount(level)))
.add(ENCHANTMENT_CHARGES_FUEL_ITEM, () -> ItemUtil.getItemName(this.getChargesFuel()));
if (this instanceof ChanceData chanceData) {
this.placeholders.add(ENCHANTMENT_CHANCE, level -> NumberUtil.format(chanceData.getTriggerChance(level)));
}
if (this instanceof PeriodicData periodicData) {
this.placeholders.add(ENCHANTMENT_INTERVAL, () -> NumberUtil.format(periodicData.getInterval() / 20D));
}
if (this instanceof PotionData potionData) {
this.placeholders.add(ENCHANTMENT_POTION_LEVEL, level -> NumberUtil.toRoman(potionData.getEffectAmplifier(level)));
this.placeholders.add(ENCHANTMENT_POTION_DURATION, level -> NumberUtil.format(potionData.getEffectDuration(level) / 20D));
this.placeholders.add(ENCHANTMENT_POTION_TYPE, () -> LangAssets.get(potionData.getEffectType()));
}
if (this.getDistributionOptions() instanceof CustomDistribution distribution) {
this.placeholders.add(ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING, () -> NumberUtil.format(distribution.getWeight(DistributionWay.ENCHANTING)));
this.placeholders.add(ENCHANTMENT_OBTAIN_CHANCE_VILLAGER, () -> NumberUtil.format(distribution.getWeight(DistributionWay.VILLAGER)));
this.placeholders.add(ENCHANTMENT_OBTAIN_CHANCE_LOOT_GENERATION, () -> NumberUtil.format(distribution.getWeight(DistributionWay.LOOT_GENERATION)));
this.placeholders.add(ENCHANTMENT_OBTAIN_CHANCE_FISHING, () -> NumberUtil.format(distribution.getWeight(DistributionWay.FISHING)));
this.placeholders.add(ENCHANTMENT_OBTAIN_CHANCE_MOB_SPAWNING, () -> NumberUtil.format(distribution.getWeight(DistributionWay.MOB_EQUIPMENT)));
}
this.loadAdditional(cfg);
this.registerListeners();
return true;
}
protected abstract void loadAdditional(@NotNull FileConfig config);
@Override
protected void onSave(@NotNull FileConfig cfg) {
}
@NotNull
private String logPrefix() {
return "[" + this.getId() + "] ";
}
protected void info(@NotNull String text) {
this.plugin.info(this.logPrefix() + text);
}
protected void warn(@NotNull String text) {
this.plugin.warn(this.logPrefix() + text);
}
protected void error(@NotNull String text) {
this.plugin.error(this.logPrefix() + text);
}
@NotNull
public PlaceholderMap getPlaceholders(int level) {
return this.placeholders.toMap(level);
}
public void addPlaceholder(@NotNull String key, @NotNull Function<Integer, String> replacer) {
this.placeholders.add(key, replacer);
}
@Override
@NotNull
public ItemCategory[] getItemCategories() {
return new ItemCategory[0];
}
@Override
public EquipmentSlot[] getSlots() {
return switch (this.getCategory()) {
case BOW, CROSSBOW, TRIDENT, FISHING_ROD, WEAPON, TOOL -> new EquipmentSlot[]{EquipmentSlot.HAND};
case ARMOR_HEAD -> new EquipmentSlot[]{EquipmentSlot.HEAD};
case ARMOR_TORSO -> new EquipmentSlot[]{EquipmentSlot.CHEST};
case ARMOR_LEGS -> new EquipmentSlot[]{EquipmentSlot.LEGS};
case ARMOR_FEET -> new EquipmentSlot[]{EquipmentSlot.FEET};
case ARMOR, WEARABLE -> new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
case BREAKABLE -> new EquipmentSlot[]{EquipmentSlot.HAND, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
case VANISHABLE -> EquipmentSlot.values();
default -> throw new IllegalStateException("Unexpected value: " + this.getCategory());
};
}
@Override
public boolean isAvailableToUse(@NotNull World world) {
Set<String> disabled = Config.ENCHANTMENTS_DISABLED_IN_WORLDS.get().getOrDefault(world.getName().toLowerCase(), Collections.emptySet());
return disabled.isEmpty() || (!disabled.contains(this.getId()) && !disabled.contains(WILDCARD));
}
@Override
public boolean isAvailableToUse(@NotNull LivingEntity entity) {
return this.isAvailableToUse(entity.getWorld());
}
@Override
public final boolean checkEnchantCategory(@NotNull ItemStack item) {
EnchantmentTarget category = this.getCategory();
if (category == EnchantmentTarget.WEAPON && ItemUtil.isAxe(item)) {
return Config.CORE_SWORD_ENCHANTS_TO_AXES.get();
}
if (category == EnchantmentTarget.BOW && item.getType() == Material.CROSSBOW) {
return Config.CORE_BOW_ENCHANTS_TO_CROSSBOW.get();
}
if ((category == EnchantmentTarget.ARMOR || category == EnchantmentTarget.ARMOR_TORSO) && item.getType() == Material.ELYTRA) {
return Config.CORE_CHESTPLATE_ENCHANTS_TO_ELYTRA.get();
}
return false;
}
@Override
public boolean checkItemCategory(@NotNull ItemStack item) {
ItemCategory[] itemCategories = this.getItemCategories();
if (itemCategories.length == 0) return false;
return Stream.of(itemCategories).anyMatch(itemCategory -> itemCategory.isIncluded(item));
}
public int generateLevel() {
return Rnd.get(this.getMinLevel(), this.getMaxLevel());
}
@Override
@NotNull
public String getNameFormatted(int level, int charges) {
String rarityFormat = this.isCurse() ? Config.ENCHANTMENTS_DISPLAY_NAME_CURSE_FORMAT.get() : Config.ENCHANTMENTS_DISPLAY_NAME_RARITY_FORMAT.get().getOrDefault(this.getRarity(), GENERIC_NAME);
String chargesFormat = "";
boolean showLevel = !Config.ENCHANTMENTS_DISPLAY_NAME_HIDE_1ST_LEVEL.get() || level > 1;
boolean showCharges = this.isChargesEnabled() && charges >= 0;
if (showCharges) {
int chargesMax = this.getChargesMax(level);
int percent = (int) Math.ceil((double) charges / (double) chargesMax * 100D);
Map.Entry<Integer, String> entry = Config.ENCHANTMENTS_CHARGES_FORMAT.get().floorEntry(percent);
if (entry != null) {
chargesFormat = entry.getValue().replace(GENERIC_AMOUNT, String.valueOf(charges));
}
}
String compName = Config.ENCHANTMENTS_DISPLAY_NAME_COMPONENT_NAME.get().replace(GENERIC_VALUE, this.getName());
String compLevel = showLevel ? Config.ENCHANTMENTS_DISPLAY_NAME_COMPONENT_LEVEL.get().replace(GENERIC_VALUE, NumberUtil.toRoman(level)) : "";
String compChrages = showCharges ? Config.ENCHANTMENTS_DISPLAY_NAME_COMPONENT_CHARGES.get().replace(GENERIC_VALUE, chargesFormat) : "";
String nameFormat = Config.ENCHANTMENTS_DISPLAY_NAME_FORMAT.get().
replace(ENCHANTMENT_NAME, compName)
.replace(ENCHANTMENT_LEVEL, compLevel)
.replace(ENCHANTMENT_CHARGES, compChrages);
return rarityFormat.replace(GENERIC_NAME, nameFormat);
}
@Override
@NotNull
public List<String> getDescriptionFormatted() {
return new ArrayList<>(this.getDescription().stream()
.map(line -> Config.ENCHANTMENTS_DISPLAY_DESCRIPTION_FORMAT.get().replace(GENERIC_DESCRIPTION, line))
.toList());
}
@Override
@NotNull
public List<String> getDescriptionReplaced(int level) {
List<String> description = new ArrayList<>(this.getDescriptionFormatted());
description.replaceAll(this.getPlaceholders(level).replacer());
return description;
}
@Override
public int getMinCost(int level) {
return this.getMinCost().getIntValue(level);
}
@Override
public int getMaxCost(int level) {
return this.getMaxCost().getIntValue(level);
}
/*@Override
public int getAnvilMergeCost(int level) {
return this.getAnvilMergeCost().getIntValue(level);
}*/
@Override
public int getChargesMax(int level) {
return this.isChargesEnabled() ? this.getChargesMax().getIntValue(level) : 0;
}
@Override
public int getChargesConsumeAmount(int level) {
return this.isChargesEnabled() ? this.getChargesConsumeAmount().getIntValue(level) : 0;
}
@Override
public int getChargesRechargeAmount(int level) {
return this.isChargesEnabled() ? this.getChargesRechargeAmount().getIntValue(level) : 0;
}
@Override
public boolean isChargesFuel(@NotNull ItemStack item) {
if (Config.ENCHANTMENTS_CHARGES_COMPARE_TYPE_ONLY.get()) {
return item.getType() == this.getChargesFuel().getType();
}
return item.isSimilar(this.getChargesFuel());
}
@Override
public boolean isOutOfCharges(@NotNull ItemStack item) {
return this.getCharges(item) == 0;
}
@Override
public boolean isFullOfCharges(@NotNull ItemStack item) {
if (!this.isChargesEnabled()) return true;
int level = EnchantUtils.getLevel(item, this.getEnchantment());
int max = this.getChargesMax(level);
return this.getCharges(item) == max;
}
@Override
public int getCharges(@NotNull ItemMeta meta) {
return this.isChargesEnabled() ? PDCUtil.getInt(meta, this.chargesKey).orElse(0) : -1;
}
@Override
public void setCharges(@NotNull ItemStack item, int level, int amount) {
if (!this.isChargesEnabled()) return;
int max = this.getChargesMax(level);
int set = Math.min(Math.abs(amount), max);
PDCUtil.set(item, this.chargesKey, set);
}
@Override
public void restoreCharges(@NotNull ItemStack item, int level) {
this.setCharges(item, level, Integer.MAX_VALUE);
}
@Override
public void fuelCharges(@NotNull ItemStack item, int level) {
int recharge = this.getChargesRechargeAmount(level);
int has = this.getCharges(item);
int set = has + recharge;
this.setCharges(item, level, set);
}
@Override
public void consumeChargesNoUpdate(@NotNull ItemStack item, int level) {
if (!this.isChargesEnabled()) return;
int charges = this.getCharges(item);
int consumeAmount = this.getChargesConsumeAmount(level);
this.setCharges(item, level, charges < consumeAmount ? 0 : Math.max(0, charges - consumeAmount));
}
@Override
public void consumeCharges(@NotNull ItemStack item, int level) {
if (!this.isChargesEnabled()) return;
this.consumeChargesNoUpdate(item, level);
EnchantUtils.updateDisplay(item);
}
@Override
@NotNull
public Enchantment getEnchantment() {
return this.enchantment;
}
@Override
public void setEnchantment(@NotNull Enchantment enchantment) {
this.enchantment = enchantment;
}
@NotNull
@Override
public Rarity getRarity() {
return rarity;
}
@Override
public void setRarity(@NotNull Rarity rarity) {
this.rarity = rarity;
}
@NotNull
@Override
public DistributionOptions getDistributionOptions() {
return distributionOptions;
}
@NotNull
public String getName() {
return displayName;
}
@Override
public void setDisplayName(@NotNull String displayName) {
this.displayName = displayName;
}
@Override
@NotNull
public List<String> getDescription() {
return description;
}
@Override
public void setDescription(@NotNull List<String> description) {
this.description = description;
}
@Override
public boolean isHiddenFromList() {
return hiddenFromList;
}
@Override
public void setHiddenFromList(boolean hiddenFromList) {
this.hiddenFromList = hiddenFromList;
}
@Override
public boolean isTreasure() {
return this.treasure;
}
@Override
public void setTreasure(boolean treasure) {
this.treasure = treasure;
}
@Override
public void setStartLevel(int levelMin) {
this.minLevel = Math.max(1, levelMin);
}
@Override
public int getMinLevel() {
return this.minLevel;
}
@Override
public void setMaxLevel(int levelMax) {
this.maxLevel = Math.max(1, levelMax);
}
@Override
public int getMaxLevel() {
return maxLevel;
}
@Override
@NotNull
public Modifier getMinCost() {
return this.minCost;
}
@Override
public void setMinCost(@NotNull Modifier minCost) {
this.minCost = minCost;
}
@Override
@NotNull
public Modifier getMaxCost() {
return this.maxCost;
}
@Override
public void setMaxCost(@NotNull Modifier maxCost) {
this.maxCost = maxCost;
}
/*@Override
@NotNull
public Modifier getAnvilMergeCost() {
return this.anvilMergeCost;
}
@Override
public void setAnvilMergeCost(@NotNull Modifier anvilMergeCost) {
this.anvilMergeCost = anvilMergeCost;
}
@Override
public int getMaxMergeLevel() {
return this.maxMergeLevel;
}
@Override
public void setMaxMergeLevel(int maxMergeLevel) {
this.maxMergeLevel = Math.min(this.getMaxLevel(), maxMergeLevel);
}*/
@Override
@NotNull
public Set<String> getConflicts() {
return this.conflicts;
}
@Override
public void setConflicts(@NotNull Set<String> conflicts) {
this.conflicts.clear();
this.conflicts.addAll(conflicts.stream().map(String::toLowerCase).collect(Collectors.toSet()));
}
@Override
public boolean hasVisualEffects() {
return visualEffects;
}
@Override
public void setVisualEffects(boolean visualEffects) {
this.visualEffects = visualEffects;
}
@Override
public boolean isChargesEnabled() {
return chargesEnabled;
}
@Override
public void setChargesEnabled(boolean chargesEnabled) {
this.chargesEnabled = chargesEnabled;
}
@Override
public boolean isChargesCustomFuel() {
return chargesCustomFuel;
}
@Override
public void setChargesCustomFuel(boolean chargesCustomFuel) {
this.chargesCustomFuel = chargesCustomFuel;
}
@Override
@NotNull
public Modifier getChargesMax() {
return chargesMax;
}
@Override
public void setChargesMax(@NotNull Modifier chargesMax) {
this.chargesMax = chargesMax;
}
@NotNull
public ItemStack getChargesFuel() {
ItemStack fuelHas = this.chargesFuel;
if (!this.isChargesCustomFuel() || fuelHas == null || fuelHas.getType().isAir()) {
return new ItemStack(Config.ENCHANTMENTS_CHARGES_FUEL_ITEM.get());
}
return new ItemStack(fuelHas);
}
@Override
public void setChargesFuel(@Nullable ItemStack chargesFuel) {
this.chargesFuel = chargesFuel;
}
@Override
@NotNull
public Modifier getChargesConsumeAmount() {
return chargesConsumeAmount;
}
@Override
public void setChargesConsumeAmount(@NotNull Modifier chargesConsumeAmount) {
this.chargesConsumeAmount = chargesConsumeAmount;
}
@Override
@NotNull
public Modifier getChargesRechargeAmount() {
return chargesRechargeAmount;
}
@Override
public void setChargesRechargeAmount(@NotNull Modifier chargesRechargeAmount) {
this.chargesRechargeAmount = chargesRechargeAmount;
}
}

View File

@ -0,0 +1,42 @@
package su.nightexpress.excellentenchants.enchantment.data;
import org.bukkit.Particle;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowSettings;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public class ArrowSettingsImpl implements ArrowSettings {
//private final EnchantmentData enchantmentData;
private final UniParticle trailParticle;
private ArrowSettingsImpl(@NotNull UniParticle trailParticle) {
//this.enchantmentData = enchantmentData;
this.trailParticle = trailParticle;
}
@NotNull
public static ArrowSettingsImpl create(@NotNull FileConfig config) {
return create(config, UniParticle.of(Particle.REDSTONE));
}
@NotNull
public static ArrowSettingsImpl create(@NotNull FileConfig config, @NotNull UniParticle particle) {
UniParticle effect = ConfigValue.create("Settings.VisualEffects.Trail",
(cfg, path, def) -> UniParticle.read(cfg, path),
(cfg, path, particle1) -> particle1.write(cfg, path),
() -> particle,
"Sets projectile particle trail effect."
).read(config);
return new ArrowSettingsImpl(effect);
}
@Override
@NotNull
public UniParticle getProjectileTrail() {
return this.trailParticle;
}
}

View File

@ -0,0 +1,39 @@
package su.nightexpress.excellentenchants.enchantment.data;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.random.Rnd;
public class ChanceSettingsImpl implements ChanceSettings {
private final Modifier triggerChance;
private ChanceSettingsImpl(@NotNull Modifier triggerChance) {
this.triggerChance = triggerChance;
}
@NotNull
public static ChanceSettingsImpl create(@NotNull FileConfig config) {
return create(config, Modifier.add(100, 0, 1, 100));
}
@NotNull
public static ChanceSettingsImpl create(@NotNull FileConfig config, @NotNull Modifier def) {
Modifier chanceMod = Modifier.read(config, "Settings.Trigger_Chance", def,
"A chance that this enchantment will be triggered.");
return new ChanceSettingsImpl(chanceMod);
}
@Override
public double getTriggerChance(int level) {
return this.triggerChance.getValue(level);
}
@Override
public boolean checkTriggerChance(int level) {
return Rnd.chance(this.getTriggerChance(level));
}
}

View File

@ -0,0 +1,154 @@
package su.nightexpress.excellentenchants.enchantment.data;
import org.bukkit.loot.LootTable;
import org.bukkit.loot.LootTables;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.distribution.DistributionOptions;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.DistributionWay;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.StringUtil;
import su.nightexpress.nightcore.util.random.Rnd;
import su.nightexpress.nightcore.util.wrapper.UniInt;
import java.util.*;
public class CustomDistribution implements DistributionOptions {
private final EnchantmentData enchantmentData;
private final Map<DistributionWay, Double> weightMap;
private final Map<DistributionWay, UniInt> levelRangeMap;
private final Set<LootTables> lootTables;
public CustomDistribution(@NotNull EnchantmentData enchantmentData) {
this.enchantmentData = enchantmentData;
this.weightMap = new HashMap<>();
this.levelRangeMap = new HashMap<>();
this.lootTables = new HashSet<>();
}
public void load(@NotNull FileConfig config) {
for (DistributionWay distributionWay : DistributionWay.values()) {
String pathName = distributionWay.getPathName();
double obtainChance = ConfigValue.create("Distribution." + pathName + ".Weight", 50D,
"Determines how often this enchantment will appear in " + pathName + ".",
"Greater value = Greater chance.").read(config);
this.weightMap.put(distributionWay, obtainChance);
int levelMin = ConfigValue.create("Distribution." + pathName + ".Level.Min", -1,
"Minimal level when obtained via " + pathName,
"Can not be less than enchantment min. level. Set -1 to use enchantment min. level.").read(config);
int levelMax = ConfigValue.create("Distribution." + pathName + ".Level.Max", -1,
"Maximal level when obtained via " + pathName,
"Can not be greater than enchantment max. level. Set -1 to use enchantment max. level.").read(config);
this.levelRangeMap.put(distributionWay, UniInt.of(levelMin, levelMax));
}
boolean isWhitelist = ConfigValue.create("Distribution." + DistributionWay.LOOT_GENERATION.getPathName() + ".LootTables.Whitelist",
false,
"When 'true', uses only loot tables listed below.",
"When 'false', uses ALL loot tables except ones listed below.",
"[Default is false]"
).read(config);
Set<LootTables> tables = ConfigValue.forSet("Distribution." + DistributionWay.LOOT_GENERATION.getPathName() + ".LootTables.List",
id -> StringUtil.getEnum(id, LootTables.class).orElse(null),
(cfg, path, set) -> cfg.set(path, set.stream().map(Enum::name).toList()),
Set.of(
LootTables.DESERT_PYRAMID
),
"Depends on Whitelist mode, this enchantment will appear on items generated by certain Loot Tables only.",
"=".repeat(15) + " EXAMPLES " + "=".repeat(15),
"==> Set 'Whitelist' on 'true' and add '" + LootTables.DESERT_PYRAMID.name() + "' to the list to make this enchantment appear on items generated inside Desert Pyramid chests only.",
"==> Set 'Whitelist' on 'false' and add '" + LootTables.DESERT_PYRAMID.name() + "' to the list to make this enchantment appear on items generated inside any structure's chests except Deset Pyramids.",
"",
"[*] Keep in mind, that Loot Generation is only applicable to items in chests. Listing here loot tables of mobs, fishing and other sources is useless.",
"Available loot table names: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/loot/LootTables.html"
).read(config);
if (isWhitelist) {
this.lootTables.addAll(tables);
}
else {
this.lootTables.addAll(Arrays.asList(LootTables.values()));
this.lootTables.removeAll(tables);
}
}
@NotNull
public Map<DistributionWay, Double> getWeightMap() {
return weightMap;
}
@NotNull
public Map<DistributionWay, UniInt> getLevelRangeMap() {
return levelRangeMap;
}
@NotNull
public Set<LootTables> getLootTables() {
return lootTables;
}
public boolean isDistributable(@NotNull DistributionWay distributionWay) {
if (distributionWay == DistributionWay.ENCHANTING && (this.enchantmentData.isTreasure() || this.enchantmentData.isCurse())) return false;
return this.getWeight(distributionWay) > 0D;
}
public boolean isGoodLootTable(@NotNull LootTable table) {
return this.getLootTables().stream().anyMatch(tables -> tables.getLootTable() == table);
}
public double getWeight(@NotNull DistributionWay distributionWay) {
return this.getWeightMap().getOrDefault(distributionWay, 0D);
}
public int getMinLevel(@NotNull DistributionWay distributionWay) {
return this.getLevelRangeMap().getOrDefault(distributionWay, UniInt.of(-1, -1)).getMinValue();
}
public int getMaxLevel(@NotNull DistributionWay distributionWay) {
return this.getLevelRangeMap().getOrDefault(distributionWay, UniInt.of(-1, -1)).getMaxValue();
}
public int generateLevel(@NotNull DistributionWay distributionWay) {
int levelCapMin = this.getMinLevel(distributionWay);
int levelCapMax = this.getMaxLevel(distributionWay);
if (levelCapMin <= 0 || levelCapMin < this.enchantmentData.getMinLevel()) levelCapMin = this.enchantmentData.getMinLevel();
if (levelCapMax <= 0 || levelCapMax > this.enchantmentData.getMaxLevel()) levelCapMax = this.enchantmentData.getMaxLevel();
return Rnd.get(levelCapMin, levelCapMax);
}
public int getLevelByEnchantCost(int xpLevel) {
int get = 0;
for (int level = this.enchantmentData.getMaxLevel(); level > this.enchantmentData.getMinLevel() - 1; level--) {
if (xpLevel >= this.enchantmentData.getMinCost(level) && xpLevel <= this.enchantmentData.getMaxCost(level)) {
get = level;
break;
}
}
return get != 0 ? this.fineLevel(get, DistributionWay.ENCHANTING) : 0;
}
public int fineLevel(int level, @NotNull DistributionWay distributionWay) {
int levelCapMin = this.getMinLevel(distributionWay);
int levelCapMax = this.getMaxLevel(distributionWay);
if (levelCapMin > 0 && level < levelCapMin) level = levelCapMin;
if (levelCapMax > 0 && level > levelCapMax) level = levelCapMax;
return level;
}
}

View File

@ -0,0 +1,55 @@
package su.nightexpress.excellentenchants.enchantment.data;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicSettings;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.nightcore.config.FileConfig;
public class PeriodSettingsImpl implements PeriodicSettings {
private final Modifier triggerInterval;
private long nextTriggerTime;
public PeriodSettingsImpl(@NotNull Modifier triggerInterval) {
this.triggerInterval = triggerInterval;
this.updateTriggerTime();
}
@NotNull
public static PeriodSettingsImpl create(@NotNull FileConfig config) {
long baseTick = Config.CORE_PASSIVE_ENCHANTS_TRIGGER_INTERVAL.get();
return create(config, Modifier.add(baseTick, 0, 1));
}
@NotNull
public static PeriodSettingsImpl create(@NotNull FileConfig config, @NotNull Modifier def) {
Modifier intervalMod = Modifier.read(config, "Settings.Trigger_Interval", def,
"Sets how often (in ticks) this enchantment will be triggered.",
"20 ticks = 1 second.");
return new PeriodSettingsImpl(intervalMod);
}
@Override
public long getInterval() {
return (long) this.triggerInterval.getValue(1);
}
@Override
public long getNextTriggerTime() {
return nextTriggerTime;
}
@Override
public boolean isTriggerTime() {
return System.currentTimeMillis() >= this.getNextTriggerTime();
}
@Override
public void updateTriggerTime() {
this.nextTriggerTime = System.currentTimeMillis() + this.getInterval() * 50L - 100L;
}
}

View File

@ -0,0 +1,100 @@
package su.nightexpress.excellentenchants.enchantment.data;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.nightcore.config.FileConfig;
public class PotionSettingsImpl implements PotionSettings {
private final PotionEffectType effectType;
private final Modifier duration;
private final Modifier amplifier;
private final boolean isPermanent;
private final boolean particles;
private PotionSettingsImpl(@NotNull PotionEffectType effectType,
boolean isPermanent,
boolean particles,
@NotNull Modifier duration,
@NotNull Modifier amplifier) {
this.effectType = effectType;
this.duration = duration;
this.amplifier = amplifier;
this.isPermanent = isPermanent;
this.particles = particles;
}
@NotNull
public static PotionSettingsImpl create(@NotNull EnchantmentData data, @NotNull FileConfig config, @NotNull PotionEffectType type, boolean isPermanent) {
return create(data, config, type, isPermanent,
Modifier.multiply(5, 1, 1),
Modifier.add(0, 1, 1, 5)
);
}
@NotNull
public static PotionSettingsImpl create(@NotNull EnchantmentData data,
@NotNull FileConfig config,
@NotNull PotionEffectType type,
boolean isPermanent,
@NotNull Modifier duration,
@NotNull Modifier amplifier) {
Modifier durationScale = Modifier.read(config, "Settings.Potion_Effect.Duration", duration,
"Potion effect duration (in seconds). This setting is useless for 'permanent' effects.");
Modifier amplifierScale = Modifier.read(config, "Settings.Potion_Effect.Level", amplifier,
"Potion effect level.");
return new PotionSettingsImpl(type, isPermanent, data.hasVisualEffects(), durationScale, amplifierScale);
}
@Override
public boolean isPermanent() {
return this.isPermanent;
}
@Override
@NotNull
public PotionEffectType getEffectType() {
return this.effectType;
}
@Override
public int getEffectDuration(int level) {
if (this.isPermanent()) {
int duration = Config.CORE_PASSIVE_ENCHANTS_TRIGGER_INTERVAL.get().intValue() * 2;
if (this.getEffectType().getKey().equals(PotionEffectType.NIGHT_VISION.getKey()) && duration < 600) {
duration += 30 * 20;
}
return duration;
}
return (int) (this.duration.getValue(level) * 20);
}
@Override
public int getEffectAmplifier(int level) {
return (int) this.amplifier.getValue(level);
}
@Override
@NotNull
public PotionEffect createEffect(int level) {
int duration = this.getEffectDuration(level);
int amplifier = Math.max(0, this.getEffectAmplifier(level) - 1);
return new PotionEffect(this.getEffectType(), duration, amplifier, false, this.particles);
}
@Override
public boolean addEffect(@NotNull LivingEntity target, int level) {
target.addPotionEffect(this.createEffect(level));
return true;
}
}

View File

@ -0,0 +1,43 @@
package su.nightexpress.excellentenchants.enchantment.data;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.distribution.VanillaOptions;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
public class VanillaDistribution implements VanillaOptions {
private boolean discoverable;
private boolean tradeable;
@Override
public void load(@NotNull FileConfig config) {
this.setTradeable(ConfigValue.create("Distribution.Tradeable",
true,
"Sets whether or not this enchantment can be populated in villager trades.").read(config));
this.setDiscoverable(ConfigValue.create("Distribution.Discoverable",
true,
"Sets whether or not this enchantment can be populated in enchanting table.").read(config));
}
@Override
public boolean isTradeable() {
return this.tradeable;
}
@Override
public void setTradeable(boolean tradeable) {
this.tradeable = tradeable;
}
@Override
public boolean isDiscoverable() {
return discoverable;
}
@Override
public void setDiscoverable(boolean discoverable) {
this.discoverable = discoverable;
}
}

View File

@ -1,459 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.manager.EventListener;
import su.nexmedia.engine.api.placeholder.PlaceholderMap;
import su.nexmedia.engine.lang.LangManager;
import su.nexmedia.engine.utils.ItemUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Periodic;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantDefaults;
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.excellentenchants.tier.Tier;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
public abstract class ExcellentEnchant /*extends Enchantment*/ implements IEnchantment {
protected final ExcellentEnchants plugin;
protected final JYML cfg;
protected final String id;
protected final EnchantDefaults defaults;
protected final NamespacedKey chargesKey;
protected final Map<Integer, PlaceholderMap> placeholdersMap;
public ExcellentEnchant(@NotNull ExcellentEnchants plugin, @NotNull String id) {
//super(NamespacedKey.minecraft(id.toLowerCase()));
this.plugin = plugin;
this.id = id.toLowerCase();//this.getKey().getKey();
this.cfg = new JYML(plugin.getDataFolder() + EnchantManager.DIR_ENCHANTS, id + ".yml");
this.chargesKey = new NamespacedKey(plugin, this.getId() + ".charges");
this.defaults = new EnchantDefaults(this);
this.placeholdersMap = new HashMap<>();
}
@NotNull
@Override
public NamespacedKey getKey() {
return EnchantUtils.createKey(this.getId());
}
public void loadSettings() {
this.cfg.reload();
this.placeholdersMap.clear();
this.getDefaults().load(this);
for (int i = this.getStartLevel(); i < this.getMaxLevel() + 1; i++) {
int level = i;
PlaceholderMap map = new PlaceholderMap()
.add(Placeholders.ENCHANTMENT_DESCRIPTION, () -> String.join("\n", this.getDescription()))
.add(Placeholders.ENCHANTMENT_ID, this::getId)
.add(Placeholders.ENCHANTMENT_NAME, this::getDisplayName)
.add(Placeholders.ENCHANTMENT_NAME_FORMATTED, () -> this.getNameFormatted(level))
.add(Placeholders.ENCHANTMENT_LEVEL, () -> NumberUtil.toRoman(level))
.add(Placeholders.ENCHANTMENT_LEVEL_MIN, () -> String.valueOf(this.getStartLevel()))
.add(Placeholders.ENCHANTMENT_LEVEL_MAX, () -> String.valueOf(this.getMaxLevel()))
.add(Placeholders.ENCHANTMENT_TIER, () -> this.getTier().getName())
.add(Placeholders.ENCHANTMENT_TIER_COLOR, () -> this.getTier().getColor())
.add(Placeholders.ENCHANTMENT_FIT_ITEM_TYPES, () -> {
if (this.getFitItemTypes().length == 0) return plugin.getLangManager().getEnum(this.getCategory());
return String.join(", ", Stream.of(this.getFitItemTypes()).map(type -> plugin.getLangManager().getEnum(type)).toList());
})
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING, () -> NumberUtil.format(this.getObtainChance(ObtainType.ENCHANTING)))
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_VILLAGER, () -> NumberUtil.format(this.getObtainChance(ObtainType.VILLAGER)))
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_LOOT_GENERATION, () -> NumberUtil.format(this.getObtainChance(ObtainType.LOOT_GENERATION)))
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_FISHING, () -> NumberUtil.format(this.getObtainChance(ObtainType.FISHING)))
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_MOB_SPAWNING, () -> NumberUtil.format(this.getObtainChance(ObtainType.MOB_SPAWNING)))
.add(Placeholders.ENCHANTMENT_CHARGES_MAX_AMOUNT, () -> NumberUtil.format(this.getChargesMax(level)))
.add(Placeholders.ENCHANTMENT_CHARGES_CONSUME_AMOUNT, () -> NumberUtil.format(this.getChargesConsumeAmount(level)))
.add(Placeholders.ENCHANTMENT_CHARGES_RECHARGE_AMOUNT, () -> NumberUtil.format(this.getChargesRechargeAmount(level)))
.add(Placeholders.ENCHANTMENT_CHARGES_FUEL_ITEM, () -> ItemUtil.getItemName(this.getChargesFuel()));
if (this instanceof Chanced chanced) {
map.add(Placeholders.ENCHANTMENT_CHANCE, () -> NumberUtil.format(chanced.getTriggerChance(level)));
}
if (this instanceof Periodic periodic) {
map.add(Placeholders.ENCHANTMENT_INTERVAL, () -> NumberUtil.format(periodic.getInterval() / 20D));
}
if (this instanceof Potioned potioned) {
map.add(Placeholders.ENCHANTMENT_POTION_LEVEL, () -> NumberUtil.toRoman(potioned.getEffectAmplifier(level)));
map.add(Placeholders.ENCHANTMENT_POTION_DURATION, () -> NumberUtil.format(potioned.getEffectDuration(level) / 20D));
map.add(Placeholders.ENCHANTMENT_POTION_TYPE, () -> LangManager.getPotionType(potioned.getEffectType()));
}
map.add(this.getTier().getPlaceholders());
this.placeholdersMap.put(level, map);
}
}
@NotNull
public PlaceholderMap getPlaceholders(int level) {
if (level > this.getMaxLevel()) level = this.getMaxLevel();
if (level < this.getStartLevel()) level = this.getStartLevel();
return this.placeholdersMap.get(level);
}
public void addPlaceholder(@NotNull String key, @NotNull Function<Integer, String> replacer) {
for (int level = this.getStartLevel(); level < this.getMaxLevel() + 1; level++) {
this.getPlaceholders(level).add(key, replacer.apply(level));
}
}
public void registerListeners() {
if (this instanceof EventListener listener) {
this.plugin.getPluginManager().registerEvents(listener, plugin);
}
}
@NotNull
public ItemCategory[] getFitItemTypes() {
//FitItemType itemType = FitItemType.getByEnchantmentTarget(this.getCategory());
//return new FitItemType[]{itemType};
return new ItemCategory[0];
}
@Override
public EquipmentSlot[] getSlots() {
return switch (this.getCategory()) {
case BOW, CROSSBOW, TRIDENT, FISHING_ROD, WEAPON, TOOL -> new EquipmentSlot[]{EquipmentSlot.HAND};
case ARMOR_HEAD -> new EquipmentSlot[]{EquipmentSlot.HEAD};
case ARMOR_TORSO -> new EquipmentSlot[]{EquipmentSlot.CHEST};
case ARMOR_LEGS -> new EquipmentSlot[]{EquipmentSlot.LEGS};
case ARMOR_FEET -> new EquipmentSlot[]{EquipmentSlot.FEET};
case ARMOR, WEARABLE -> new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
case BREAKABLE -> new EquipmentSlot[]{EquipmentSlot.HAND, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
case VANISHABLE -> EquipmentSlot.values();
default -> throw new IllegalStateException("Unexpected value: " + this.getCategory());
};
/*Set<EquipmentSlot> slots = new HashSet<>();
for (FitItemType itemType : this.getFitItemTypes()) {
slots.addAll(Arrays.asList(itemType.getSlots()));
}
return slots.toArray(new EquipmentSlot[0]);*/
}
public boolean isDisabledInWorld(@NotNull World world) {
Set<String> disabled = Config.ENCHANTMENTS_DISABLED_IN_WORLDS.get().getOrDefault(world.getName(), Collections.emptySet());
return disabled.contains(this.getKey().getKey()) || disabled.contains(Placeholders.WILDCARD);
}
@Override
public boolean isAvailableToUse(@NotNull LivingEntity entity) {
return !this.isDisabledInWorld(entity.getWorld());
}
@NotNull
public JYML getConfig() {
return this.cfg;
}
@NotNull
public String getId() {
return this.id;
}
@NotNull
public EnchantDefaults getDefaults() {
return defaults;
}
/*@NotNull
@Override
public String getName() {
return getId().toUpperCase();
}*/
@NotNull
public String getDisplayName() {
return this.getDefaults().getDisplayName();
}
@NotNull
public String getNameFormatted(int level) {
String name = this.getTier().getColor() + this.getDisplayName();
if (level > 1 || this.getMaxLevel() > 1) {
name += " " + NumberUtil.toRoman(level);
}
return name;
}
@NotNull
public String getNameFormatted(int level, int charges) {
if (!this.isChargesEnabled() || charges < 0) return this.getNameFormatted(level);
int chargesMax = this.getChargesMax(level);
int percent = (int) Math.ceil((double) charges / (double) chargesMax * 100D);
Map.Entry<Integer, String> entry = Config.ENCHANTMENTS_CHARGES_FORMAT.get().floorEntry(percent);
if (entry == null) return this.getNameFormatted(level);
String format = entry.getValue().replace(Placeholders.GENERIC_AMOUNT, String.valueOf(charges));
return this.getNameFormatted(level) + " " + format;
}
@NotNull
public List<String> getDescription() {
return this.getDefaults().getDescription();
}
@NotNull
public List<String> getDescription(int level) {
List<String> description = new ArrayList<>(this.getDescription());
description.replaceAll(this.getPlaceholders(level).replacer());
return description;
}
@NotNull
public List<String> formatDescription() {
return new ArrayList<>(this.getDescription().stream()
.map(line -> Config.ENCHANTMENTS_DESCRIPTION_FORMAT.get().replace(Placeholders.GENERIC_DESCRIPTION, line))
.toList());
}
@NotNull
public List<String> formatDescription(int level) {
return new ArrayList<>(this.getDescription(level).stream()
.map(line -> Config.ENCHANTMENTS_DESCRIPTION_FORMAT.get().replace(Placeholders.GENERIC_DESCRIPTION, line))
.toList());
}
public boolean hasConflicts() {
return !this.getConflicts().isEmpty();
}
@NotNull
public Set<String> getConflicts() {
return this.getDefaults().getConflicts();
}
@NotNull
public Tier getTier() {
return this.getDefaults().getTier();
}
@Override
public int getMaxLevel() {
return this.getDefaults().getLevelMax();
}
@Override
public int getStartLevel() {
return this.getDefaults().getLevelMin();
}
public int getMaxMergeLevel() {
return this.getDefaults().getMaxMergeLevel() < 0 ? this.getMaxLevel() : this.getDefaults().getMaxMergeLevel();
}
public int getLevelByEnchantCost(int expLevel) {
int get = this.getDefaults().getLevelByEnchantCost().getValues().entrySet().stream()
.filter(en -> expLevel >= en.getValue().intValue()).max(Comparator.comparingInt(Map.Entry::getKey))
.map(Map.Entry::getKey).orElse(0);
return get != 0 ? this.fineLevel(get, ObtainType.ENCHANTING) : 0;
}
public boolean isObtainable(@NotNull ObtainType obtainType) {
if (obtainType == ObtainType.ENCHANTING && (this.isTreasure() || this.isCurse())) return false;
return this.getObtainChance(obtainType) > 0D;
}
public double getObtainChance(@NotNull ObtainType obtainType) {
return this.getDefaults().getObtainChance().getOrDefault(obtainType, 0D);
}
public int getObtainLevelMin(@NotNull ObtainType obtainType) {
return this.getDefaults().getObtainLevelCap().getOrDefault(obtainType, new int[]{-1, -1})[0];
}
public int getObtainLevelMax(@NotNull ObtainType obtainType) {
return this.getDefaults().getObtainLevelCap().getOrDefault(obtainType, new int[]{-1, -1})[1];
}
public int fineLevel(int level, @NotNull ObtainType obtainType) {
int levelCapMin = this.getObtainLevelMin(obtainType);
int levelCapMax = this.getObtainLevelMax(obtainType);
if (levelCapMin > 0 && level < levelCapMin) level = levelCapMin;
if (levelCapMax > 0 && level > levelCapMax) level = levelCapMax;
return level;
}
public int generateLevel() {
return Rnd.get(this.getStartLevel(), this.getMaxLevel());
}
public int generateLevel(@NotNull ObtainType obtainType) {
int levelCapMin = this.getObtainLevelMin(obtainType);
int levelCapMax = this.getObtainLevelMax(obtainType);
if (levelCapMin <= 0 || levelCapMin < this.getStartLevel()) levelCapMin = this.getStartLevel();
if (levelCapMax <= 0 || levelCapMax > this.getMaxLevel()) levelCapMax = this.getMaxLevel();
return Rnd.get(levelCapMin, levelCapMax);
}
public int getAnvilMergeCost(int level) {
return (int) this.getDefaults().getAnvilMergeCost().getValue(level);
}
/*@Override
@Deprecated
public final boolean conflictsWith(@NotNull Enchantment enchantment) {
return this.getConflicts().contains(enchantment.getKey().getKey());
}*/
@Deprecated
public Enchantment getBackend() {
return EnchantUtils.getEnchantment(this.getKey());
}
@Override
public final boolean checkEnchantCategory(@NotNull ItemStack item) {
EnchantmentTarget category = this.getCategory();
if (category == EnchantmentTarget.WEAPON && ItemUtil.isAxe(item)) {
return Config.ENCHANTMENTS_ITEM_SWORD_ENCHANTS_TO_AXES.get();
}
if (category == EnchantmentTarget.BOW && item.getType() == Material.CROSSBOW) {
return Config.ENCHANTMENTS_ITEM_BOW_ENCHANTS_TO_CROSSBOW.get();
}
if ((category == EnchantmentTarget.ARMOR || category == EnchantmentTarget.ARMOR_TORSO) && item.getType() == Material.ELYTRA) {
return Config.ENCHANTMENTS_ITEM_CHESTPLATE_ENCHANTS_TO_ELYTRA.get();
}
return false;
}
@Override
public boolean checkItemCategory(@NotNull ItemStack item) {
ItemCategory[] itemCategories = this.getFitItemTypes();
if (itemCategories.length == 0) return false;
return Stream.of(itemCategories).anyMatch(itemCategory -> itemCategory.isIncluded(item));
}
@Override
public boolean isCurse() {
return false;
}
@Override
public final boolean isTreasure() {
return this.getDefaults().isTreasure();
}
@Override
public boolean isTradeable() {
return this.getDefaults().isTradeable();
}
@Override
public boolean isDiscoverable() {
return this.getDefaults().isDiscoverable();
}
public boolean hasVisualEffects() {
return this.getDefaults().isVisualEffects();
}
public boolean isChargesEnabled() {
return Config.ENCHANTMENTS_CHARGES_ENABLED.get() && this.getDefaults().isChargesEnabled();
}
public boolean isChargesCustomFuel() {
return this.getDefaults().isChargesCustomFuel();
}
public int getChargesMax(int level) {
return this.isChargesEnabled() ? (int) this.getDefaults().getChargesMax().getValue(level) : 0;
}
public int getChargesConsumeAmount(int level) {
return this.isChargesEnabled() ? (int) this.getDefaults().getChargesConsumeAmount().getValue(level) : 0;
}
public int getChargesRechargeAmount(int level) {
return this.isChargesEnabled() ? (int) this.getDefaults().getChargesRechargeAmount().getValue(level) : 0;
}
@NotNull
public ItemStack getChargesFuel() {
ItemStack fuelHas = this.getDefaults().getChargesFuel();
if (!this.isChargesCustomFuel() || fuelHas == null || fuelHas.getType().isAir()) {
return Config.ENCHANTMENTS_CHARGES_FUEL_ITEM.get();
}
return new ItemStack(fuelHas);
}
public boolean isChargesFuel(@NotNull ItemStack item) {
if (Config.ENCHANTMENTS_CHARGES_COMPARE_TYPE_ONLY.get()) {
return item.getType() == this.getChargesFuel().getType();
}
return item.isSimilar(this.getChargesFuel());
}
@NotNull
public NamespacedKey getChargesKey() {
return chargesKey;
}
@Override
public boolean isOutOfCharges(@NotNull ItemStack item) {
return EnchantUtils.isOutOfCharges(item, this);
}
@Override
public boolean isFullOfCharges(@NotNull ItemStack item) {
return EnchantUtils.isFullOfCharges(item, this);
}
@Override
public int getCharges(@NotNull ItemStack item) {
return EnchantUtils.getCharges(item, this);
}
@Override
public void consumeChargesNoUpdate(@NotNull ItemStack item, int level) {
if (!this.isChargesEnabled()) return;
EnchantUtils.consumeCharges(item, this, level);
}
@Override
public void consumeCharges(@NotNull ItemStack item, int level) {
if (!this.isChargesEnabled()) return;
this.consumeChargesNoUpdate(item, level);
EnchantUtils.updateDisplay(item);
}
}

View File

@ -1,59 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
public class AquamanEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
public static final String ID = "aquaman";
private PotionImplementation potionImplementation;
private PeriodImplementation periodImplementation;
public AquamanEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setLevelMax(1);
this.getDefaults().setTier(0.4);
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
}
@Override
public void loadSettings() {
super.loadSettings();
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.WATER_BREATHING, true);
this.periodImplementation = PeriodImplementation.create(this, "100");
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
}
@NotNull
@Override
public PeriodImplementation getPeriodImplementation() {
return periodImplementation;
}
@Override
@NotNull
public EnchantmentTarget getCategory() {
return EnchantmentTarget.ARMOR_HEAD;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
return this.addEffect(entity, level);
}
}

View File

@ -7,51 +7,57 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
public class ColdSteelEnchant extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class ColdSteelEnchant extends AbstractEnchantmentData implements ChanceData, PotionData, CombatEnchant {
public static final String ID = "cold_steel";
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
public ColdSteelEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to apply " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
this.getDefaults().setTier(0.3);
this.getDefaults().setLevelMax(3);
private ChanceSettingsImpl chanceSettings;
private PotionSettingsImpl potionSettings;
public ColdSteelEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to apply " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " (" + ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
this.setRarity(Rarity.COMMON);
this.setMaxLevel(3);
}
@Override
public void loadSettings() {
super.loadSettings();
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(8, 2, 1));
this.chanceImplementation = ChanceImplementation.create(this,
"60 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.SLOW_DIGGING, false,
"4 + " + Placeholders.ENCHANTMENT_LEVEL,
Placeholders.ENCHANTMENT_LEVEL);
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.SLOW_DIGGING, false,
Modifier.add(4, 1, 1, 300),
Modifier.add(0, 1,1, 5)
);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
public PotionSettings getPotionSettings() {
return potionSettings;
}
@Override

View File

@ -8,51 +8,58 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public class DarknessCloakEnchant extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class DarknessCloakEnchant extends AbstractEnchantmentData implements ChanceData, PotionData, CombatEnchant {
public static final String ID = "darkness_cloak";
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
private ChanceSettingsImpl chanceSettings;
private PotionSettingsImpl potionSettings;
public DarknessCloakEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to apply " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.2);
public DarknessCloakEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to apply " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " (" + ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
this.setMaxLevel(3);
this.setRarity(Rarity.COMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this,
"20.0 * " + Placeholders.ENCHANTMENT_LEVEL + " * 0.75");
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(11, 3, 1));
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.DARKNESS, false,
"2.5" + Placeholders.ENCHANTMENT_LEVEL,
Placeholders.ENCHANTMENT_LEVEL);
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.DARKNESS, false,
Modifier.add(5, 1, 1, 300),
Modifier.add(0, 1, 1, 10)
);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
public PotionSettings getPotionSettings() {
return potionSettings;
}
@Override

View File

@ -7,55 +7,59 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.api.manager.EventListener;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.manager.SimpeListener;
import su.nightexpress.nightcore.util.NumberUtil;
import java.io.File;
import java.util.Set;
public class ElementalProtectionEnchant extends ExcellentEnchant implements GenericEnchant, EventListener {
import static su.nightexpress.excellentenchants.Placeholders.*;
public static final String ID = "elemental_protection";
public static final String PLACEHOLDER_PROTECTION_AMOUNT = "%enchantment_protection_amount%";
public static final String PLACEHOLDER_PROTECTION_CAPACITY = "%enchantment_protection_capacity%";
public class ElementalProtectionEnchant extends AbstractEnchantmentData implements SimpeListener, GenericEnchant {
public static final String ID = "elemental_protection";
private static final Set<EntityDamageEvent.DamageCause> DAMAGE_CAUSES = Set.of(
EntityDamageEvent.DamageCause.POISON, EntityDamageEvent.DamageCause.WITHER,
EntityDamageEvent.DamageCause.MAGIC, EntityDamageEvent.DamageCause.FREEZE,
EntityDamageEvent.DamageCause.LIGHTNING);
private EnchantScaler protectionAmount;
private double protectionCapacity;
private boolean protectionAsModifier;
private Modifier protectionAmount;
private double protectionCapacity;
private boolean protectionAsModifier;
public ElementalProtectionEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Reduces Poison, Magic, Wither, Lightning, Freeze damage by " + PLACEHOLDER_PROTECTION_AMOUNT + ".");
this.getDefaults().setLevelMax(5);
this.getDefaults().setTier(0.2);
public ElementalProtectionEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription("Reduces Poison, Magic, Wither, Lightning, Freeze damage by " + GENERIC_AMOUNT + "%.");
this.setMaxLevel(5);
this.setRarity(Rarity.COMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
protected void loadAdditional(@NotNull FileConfig config) {
this.protectionAmount = Modifier.read(config, "Settings.Protection.Amount",
Modifier.add(0, 5, 1, 100),
"Protection amount given by enchantment.");
this.protectionAmount = EnchantScaler.read(this, "Settings.Protection.Amount",
"0.05 * " + Placeholders.ENCHANTMENT_LEVEL,
"How protection the enchantment will have?");
this.protectionCapacity = JOption.create("Settings.Protection.Capacity", 1D,
"Maximal possible protection value from all armor pieces together.").read(cfg);
this.protectionAsModifier = JOption.create("Settings.Protection.As_Modifier", false,
"When 'true' damage will be reduced by a percent of protection value.",
"When 'false' damage will be reduced by a plain protection value.").read(cfg);
this.protectionCapacity = ConfigValue.create("Settings.Protection.Capacity",
100D,
"Maximal possible protection value from all armor pieces together.").read(config);
this.addPlaceholder(PLACEHOLDER_PROTECTION_AMOUNT, level -> NumberUtil.format(this.getProtectionAmount(level)));
this.addPlaceholder(PLACEHOLDER_PROTECTION_CAPACITY, level -> NumberUtil.format(this.getProtectionCapacity()));
this.protectionAsModifier = ConfigValue.create("Settings.Protection.As_Modifier",
true,
"Determines if Protection value is percent based or plain amount."
).read(config);
this.addPlaceholder(GENERIC_AMOUNT, level -> NumberUtil.format(this.getProtectionAmount(level)));
this.addPlaceholder(GENERIC_MAX, level -> NumberUtil.format(this.getProtectionCapacity()));
}
@NotNull
@ -84,7 +88,7 @@ public class ElementalProtectionEnchant extends ExcellentEnchant implements Gene
double protectionAmount = 0D;
for (ItemStack armor : EnchantUtils.getEnchantedEquipment(entity).values()) {
int level = EnchantUtils.getLevel(armor, this.getBackend());
int level = EnchantUtils.getLevel(armor, this.getEnchantment());
if (level <= 0) continue;
protectionAmount += this.getProtectionAmount(level);
@ -96,11 +100,9 @@ public class ElementalProtectionEnchant extends ExcellentEnchant implements Gene
protectionAmount = this.getProtectionCapacity();
}
if (this.isProtectionAsModifier()) {
event.setDamage(Math.max(0, event.getDamage() * (1D - protectionAmount)));
}
else {
event.setDamage(Math.max(0, event.getDamage() - protectionAmount));
}
double damage = event.getDamage();
double blocked = this.isProtectionAsModifier() ? damage * (1D - protectionAmount) : damage - protectionAmount;
event.setDamage(Math.max(0, blocked));
}
}

View File

@ -1,54 +1,61 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import su.nightexpress.nightcore.util.wrapper.UniSound;
public class FireShieldEnchant extends ExcellentEnchant implements Chanced, CombatEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class FireShieldEnchant extends AbstractEnchantmentData implements ChanceData, CombatEnchant {
public static final String ID = "fire_shield";
public static final String PLACEHOLDER_FIRE_DURATION = "%enchantment_fire_duration%";
private EnchantScaler fireDuration;
private ChanceImplementation chanceImplementation;
private Modifier fireDuration;
private ChanceSettingsImpl chanceSettings;
public FireShieldEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to ignite the attacker for " + PLACEHOLDER_FIRE_DURATION + "s.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.4);
public FireShieldEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to ignite attackers for " + GENERIC_DURATION + "s.");
this.setMaxLevel(3);
this.setRarity(Rarity.UNCOMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(3, 2, 1, 100));
this.chanceImplementation = ChanceImplementation.create(this,
Placeholders.ENCHANTMENT_LEVEL + " * 15.0");
this.fireDuration = EnchantScaler.read(this, "Settings.Fire.Duration",
"2.5 * " + Placeholders.ENCHANTMENT_LEVEL,
this.fireDuration = Modifier.read(config, "Settings.Fire.Duration",
Modifier.multiply(2, 1, 1, 600),
"Sets the fire duration (in seconds).",
"If entity's current fire ticks amount is less than this value, it will be set to this value.",
"If entity's current fire ticks amount is greater than this value, it won't be changed.");
this.addPlaceholder(PLACEHOLDER_FIRE_DURATION, level -> NumberUtil.format(this.getFireDuration(level)));
this.addPlaceholder(GENERIC_DURATION, level -> NumberUtil.format(this.getFireDuration(level)));
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@ -82,6 +89,11 @@ public class FireShieldEnchant extends ExcellentEnchant implements Chanced, Comb
int ticksHas = damager.getFireTicks();
if (ticksHas >= ticksToSet) return false;
if (this.hasVisualEffects()) {
UniParticle.of(Particle.FLAME).play(victim.getEyeLocation(), 0.5, 0.1, 35);
UniSound.of(Sound.ITEM_FIRECHARGE_USE).play(victim.getLocation());
}
damager.setFireTicks(ticksToSet);
return true;
}

View File

@ -18,69 +18,90 @@ import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.Version;
import su.nexmedia.engine.api.manager.EventListener;
import su.nexmedia.engine.api.server.AbstractTask;
import su.nexmedia.engine.utils.Pair;
import su.nexmedia.engine.utils.random.Rnd;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.Cleanable;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.manager.SimpeListener;
import su.nightexpress.nightcore.util.Pair;
import su.nightexpress.nightcore.util.random.Rnd;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public class FlameWalkerEnchant extends ExcellentEnchant implements GenericEnchant, EventListener, Cleanable {
public class FlameWalkerEnchant extends AbstractEnchantmentData implements GenericEnchant, SimpeListener {
public static final String ID = "flame_walker";
private static final BlockFace[] FACES = {BlockFace.SOUTH, BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST};
private static final Map<Block, Pair<Long, Integer>> BLOCKS_TO_DESTROY = new ConcurrentHashMap<>();
private static final BlockFace[] FACES = {BlockFace.SOUTH, BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST};
private static final Map<Location, Pair<Long, Integer>> BLOCKS_TO_DESTROY = new ConcurrentHashMap<>();
private EnchantScaler blockDecayTime;
private BlockTickTask blockTickTask;
private Modifier blockDecayTime;
public FlameWalkerEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Ability to walk on lava and magma blocks without getting damage.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.7);
this.getDefaults().getConflicts().add(Enchantment.FROST_WALKER.getKey().getKey());
this.blockTickTask = new BlockTickTask(plugin);
this.blockTickTask.start();
public FlameWalkerEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription("Ability to walk on lava, ignore magma block damage.");
this.setMaxLevel(3);
this.setRarity(Rarity.RARE);
this.setConflicts(Enchantment.FROST_WALKER.getKey().getKey());
}
@Override
public void loadSettings() {
super.loadSettings();
this.blockDecayTime = EnchantScaler.read(this, "Settings.Block_Decay", "12.0",
protected void loadAdditional(@NotNull FileConfig config) {
this.blockDecayTime = Modifier.read(config, "Settings.Block_Decay",
Modifier.add(8, 1, 1, 120),
"Sets up to how long (in seconds) blocks will stay before turn back to lava.");
}
@Override
public void clear() {
if (this.blockTickTask != null) {
this.blockTickTask.stop();
this.blockTickTask = null;
}
BLOCKS_TO_DESTROY.keySet().forEach(block -> block.setType(Material.LAVA));
public static void clear() {
BLOCKS_TO_DESTROY.keySet().forEach(location -> location.getBlock().setType(Material.LAVA));
BLOCKS_TO_DESTROY.clear();
}
public static void addBlock(@NotNull Block block, double seconds) {
BLOCKS_TO_DESTROY.put(block, Pair.of(System.currentTimeMillis() + (long) seconds * 1000L, Rnd.get(100)));
BLOCKS_TO_DESTROY.put(block.getLocation(), Pair.of(System.currentTimeMillis() + (long) seconds * 1000L, Rnd.get(1000)));
}
public static boolean isBlock(@NotNull Block block) {
return BLOCKS_TO_DESTROY.containsKey(block);
return BLOCKS_TO_DESTROY.containsKey(block.getLocation());
}
public static void tickBlocks() {
long now = System.currentTimeMillis();
BLOCKS_TO_DESTROY.keySet().removeIf(location -> location.getBlock().isLiquid() || location.getBlock().getType() != Material.MAGMA_BLOCK);
BLOCKS_TO_DESTROY.forEach((location, pair) -> {
Block block = location.getBlock();
long time = pair.getFirst();
if (now >= time) {
block.getWorld().getPlayers().forEach(player -> {
player.sendBlockDamage(location, 0F, pair.getSecond());
});
block.setType(Material.LAVA);
UniParticle.blockCrack(Material.MAGMA_BLOCK).play(location, 0.5, 0.7, 0.5, 0.03, 30);
return;
}
long diff = TimeUnit.MILLISECONDS.toSeconds(time - now);
float progress = (float) (1D - Math.min(1D, diff / 5D));
if (progress > 1F) progress = 1F;
if (progress < 0F) progress = 0F;
float finalProgress = progress;
block.getWorld().getPlayers().forEach(player -> {
player.sendBlockDamage(location, finalProgress, pair.getSecond());
});
});
}
@Override
@ -106,16 +127,20 @@ public class FlameWalkerEnchant extends ExcellentEnchant implements GenericEncha
ItemStack boots = player.getInventory().getBoots();
if (boots == null || boots.getType().isAir()) return;
int level = EnchantUtils.getLevel(boots, this.getBackend());
int level = EnchantUtils.getLevel(boots, this.getEnchantment());
if (level <= 0) return;
Block bTo = to.getBlock().getRelative(BlockFace.DOWN);
boolean hasLava = Stream.of(FACES).anyMatch(face -> bTo.getRelative(face).getType() == Material.LAVA);
if (!hasLava) return;
plugin.getEnchantNMS().handleFlameWalker(player, player.getLocation(), level).forEach(block -> {
Set<Block> blocks = plugin.getEnchantNMS().handleFlameWalker(player, player.getLocation(), level);
blocks.forEach(block -> {
addBlock(block, Rnd.getDouble(this.getBlockDecayTime(level)) + 1);
});
if (!blocks.isEmpty()) {
this.consumeCharges(boots, level);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -140,7 +165,7 @@ public class FlameWalkerEnchant extends ExcellentEnchant implements GenericEncha
private void processExplosion(@NotNull List<Block> blocks) {
blocks.removeIf(block -> {
if (isBlock(block)) {
block.setType(Material.AIR);
block.setType(Material.LAVA);
return true;
}
return false;
@ -159,52 +184,10 @@ public class FlameWalkerEnchant extends ExcellentEnchant implements GenericEncha
ItemStack boots = equipment.getBoots();
if (boots == null || boots.getType().isAir()) return;
int level = EnchantUtils.getLevel(boots, this.getBackend());
int level = EnchantUtils.getLevel(boots, this.getEnchantment());
if (level <= 0) return;
event.setCancelled(true);
}
static class BlockTickTask extends AbstractTask<ExcellentEnchants> {
public BlockTickTask(@NotNull ExcellentEnchants plugin) {
super(plugin, 1, false);
}
@Override
public void action() {
long now = System.currentTimeMillis();
BLOCKS_TO_DESTROY.keySet().removeIf(block -> {
if (block.isEmpty() || block.getType() != Material.MAGMA_BLOCK) return true;
Pair<Long, Integer> pair = BLOCKS_TO_DESTROY.get(block);
long time = pair.getFirst();
if (now >= time) {
if (Version.isAtLeast(Version.V1_19_R3)) {
block.getWorld().getPlayers().forEach(player -> {
player.sendBlockDamage(block.getLocation(), 0F, pair.getSecond());
});
}
block.setType(Material.LAVA);
UniParticle.blockCrack(Material.MAGMA_BLOCK).play(block.getLocation(), 0.5, 0.7, 0.5, 0.03, 30);
return true;
}
else if (Version.isAtLeast(Version.V1_19_R3)) {
long diff = TimeUnit.MILLISECONDS.toSeconds(time - now);
float progress = (float) (1D - Math.min(1D, diff / 5D));
if (progress > 1F) progress = 1F;
if (progress < 0F) progress = 0F;
float finalProgress = progress;
block.getWorld().getPlayers().forEach(player -> {
player.sendBlockDamage(block.getLocation(), finalProgress, pair.getSecond());
});
}
return false;
});
}
this.consumeCharges(boots, level);
}
}

View File

@ -7,50 +7,57 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
public class HardenedEnchant extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class HardenedEnchant extends AbstractEnchantmentData implements ChanceData, PotionData, CombatEnchant {
public static final String ID = "hardened";
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
private ChanceSettingsImpl chanceSettings;
private PotionSettingsImpl potionSettings;
public HardenedEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to obtain " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) when damaged.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.4);
public HardenedEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to get " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " (" + ENCHANTMENT_POTION_DURATION + "s.) when damaged.");
this.setMaxLevel(3);
this.setRarity(Rarity.UNCOMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this,
"30.0 * " + Placeholders.ENCHANTMENT_LEVEL);
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(2, 2, 1, 100));
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.DAMAGE_RESISTANCE, false,
"3.0" + Placeholders.ENCHANTMENT_LEVEL,
Placeholders.ENCHANTMENT_LEVEL);
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.DAMAGE_RESISTANCE, false,
Modifier.add(2, 1, 1, 300),
Modifier.add(0, 1, 1.5, 5)
);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
public PotionSettings getPotionSettings() {
return potionSettings;
}
@Override

View File

@ -1,6 +1,8 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventPriority;
@ -8,37 +10,47 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import su.nightexpress.nightcore.util.wrapper.UniSound;
public class IceShieldEnchant extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class IceShieldEnchant extends AbstractEnchantmentData implements ChanceData, PotionData, CombatEnchant {
public static final String ID = "ice_shield";
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
private ChanceSettingsImpl chanceSettings;
private PotionSettingsImpl potionSettings;
public IceShieldEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to freeze and apply " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.1);
public IceShieldEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to freeze and apply " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " (" + ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
this.setMaxLevel(3);
this.setRarity(Rarity.COMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this, "25.0 * " + Placeholders.ENCHANTMENT_LEVEL);
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.SLOW, false,
"3.0 + " + Placeholders.ENCHANTMENT_LEVEL,
Placeholders.ENCHANTMENT_LEVEL);
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(4, 4, 1, 100));
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.SLOW, false,
Modifier.add(2, 2, 1, 300),
Modifier.add(0, 1, 1, 5)
);
}
@NotNull
@ -55,14 +67,14 @@ public class IceShieldEnchant extends ExcellentEnchant implements Chanced, Potio
@Override
@NotNull
public Chanced getChanceImplementation() {
return this.chanceImplementation;
public ChanceSettings getChanceSettings() {
return this.chanceSettings;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
public PotionSettings getPotionSettings() {
return potionSettings;
}
@Override
@ -78,8 +90,11 @@ public class IceShieldEnchant extends ExcellentEnchant implements Chanced, Potio
damager.setFreezeTicks(damager.getMaxFreezeTicks());
if (this.hasVisualEffects()) {
UniParticle.blockCrack(Material.ICE).play(damager.getEyeLocation(), 0.25, 0.1, 20);
UniParticle.blockCrack(Material.ICE).play(victim.getEyeLocation(), 0.5, 0.1, 35);
UniParticle.of(Particle.CLOUD).play(victim.getEyeLocation(), 0.25, 0.1, 25);
UniSound.of(Sound.BLOCK_GLASS_BREAK).play(victim.getLocation());
}
return true;
}
}

View File

@ -5,45 +5,51 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.PeriodSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
public class JumpingEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class JumpingEnchant extends AbstractEnchantmentData implements PotionData, PassiveEnchant {
public static final String ID = "bunny_hop";
private PotionImplementation potionImplementation;
private PeriodImplementation periodImplementation;
private PotionSettingsImpl potionSettings;
private PeriodSettingsImpl periodSettings;
public JumpingEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.1);
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
public JumpingEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setMaxLevel(3);
this.setRarity(Rarity.COMMON);
this.setDescription("Grants permanent " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " effect.");
}
@Override
public void loadSettings() {
super.loadSettings();
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.JUMP, true);
this.periodImplementation = PeriodImplementation.create(this, "100");
protected void loadAdditional(@NotNull FileConfig config) {
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.JUMP, true);
this.periodSettings = PeriodSettingsImpl.create(config);
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
public PotionSettings getPotionSettings() {
return potionSettings;
}
@NotNull
@Override
public PeriodImplementation getPeriodImplementation() {
return periodImplementation;
public PeriodicSettings getPeriodSettings() {
return periodSettings;
}
@Override

View File

@ -1,5 +1,6 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
@ -12,56 +13,59 @@ import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityResurrectEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.api.manager.EventListener;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.manager.SimpeListener;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public class KamikadzeEnchant extends ExcellentEnchant implements Chanced, DeathEnchant, EventListener {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class KamikadzeEnchant extends AbstractEnchantmentData implements ChanceData, DeathEnchant, SimpeListener {
public static final String ID = "self_destruction";
private static final String PLACEHOLDER_EXPLOSION_POWER = "%enchantment_explosion_power%";
private EnchantScaler explosionSize;
private boolean applyOnResurrect;
private ChanceImplementation chanceImplementation;
private Modifier explosionSize;
private boolean applyOnResurrect;
private ChanceSettingsImpl chanceSettings;
private Entity exploder;
public KamikadzeEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("%enchantment_trigger_chance%% chance to create an explosion on death.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.3);
public KamikadzeEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to create an explosion on death.");
this.setMaxLevel(3);
this.setRarity(Rarity.UNCOMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this,
"20.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 10");
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(0, 5, 1, 100));
this.applyOnResurrect = JOption.create("Settings.Apply_On_Resurrect", true,
this.applyOnResurrect = ConfigValue.create("Settings.Apply_On_Resurrect",
true,
"Sets whether or not enchantment will trigger on resurrect (when a totem is used)."
).read(cfg);
).read(config);
this.explosionSize = EnchantScaler.read(this, "Settings.Explosion.Size",
"1.0" + Placeholders.ENCHANTMENT_LEVEL,
"A size of the explosion. The more size - the bigger the damage.");
this.addPlaceholder(PLACEHOLDER_EXPLOSION_POWER, level -> NumberUtil.format(this.getExplosionSize(level)));
this.explosionSize = Modifier.read(config, "Settings.Explosion.Size",
Modifier.add(1, 1, 1, 5),
"A size of the explosion. The more size - the bigger the damage."
);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@Override
@ -82,9 +86,16 @@ public class KamikadzeEnchant extends ExcellentEnchant implements Chanced, Death
if (!this.checkTriggerChance(level)) return false;
float size = (float) this.getExplosionSize(level);
this.exploder = entity;
boolean exploded = entity.getWorld().createExplosion(entity.getLocation(), size, false, false, entity);
this.exploder = null;
if (exploded && this.hasVisualEffects()) {
UniParticle.of(Particle.SMOKE_NORMAL).play(entity.getEyeLocation(), 0.5, 0.1, 60);
UniParticle.of(Particle.LAVA).play(entity.getEyeLocation(), 1.25, 0.1, 100);
}
return exploded;
}

View File

@ -5,45 +5,51 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.PeriodSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
public class NightVisionEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class NightVisionEnchant extends AbstractEnchantmentData implements PotionData, PassiveEnchant {
public static final String ID = "night_vision";
private PotionImplementation potionImplementation;
private PeriodImplementation periodImplementation;
private PotionSettingsImpl potionSettings;
private PeriodSettingsImpl periodSettings;
public NightVisionEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
this.getDefaults().setLevelMax(1);
this.getDefaults().setTier(0.7);
public NightVisionEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription("Grants permanent " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " effect.");
this.setMaxLevel(1);
this.setRarity(Rarity.VERY_RARE);
}
@Override
public void loadSettings() {
super.loadSettings();
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.NIGHT_VISION, true);
this.periodImplementation = PeriodImplementation.create(this, "100");
protected void loadAdditional(@NotNull FileConfig config) {
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.NIGHT_VISION, true);
this.periodSettings = PeriodSettingsImpl.create(config);
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
public PotionSettings getPotionSettings() {
return potionSettings;
}
@NotNull
@Override
public PeriodImplementation getPeriodImplementation() {
return periodImplementation;
public PeriodicSettings getPeriodSettings() {
return periodSettings;
}
@Override

View File

@ -6,70 +6,79 @@ import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.EntityUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PeriodSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.EntityUtil;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public class RegrowthEnchant extends ExcellentEnchant implements Chanced, PassiveEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class RegrowthEnchant extends AbstractEnchantmentData implements ChanceData, PassiveEnchant {
public static final String ID = "regrowth";
private static final String PLACEHOLDER_HEAL_AMOUNT = "%enchantment_heal_amount%";
private static final String PLACEHOLDER_HEAL_MIN_HEALTH = "%enchantment_heal_min_health%";
private static final String PLACEHOLDER_HEAL_MAX_HEALTH = "%enchantment_heal_max_health%";
private Modifier minHealth;
private Modifier maxHealth;
private Modifier healAmount;
private EnchantScaler healMinHealth;
private EnchantScaler healMaxHealth;
private EnchantScaler healAmount;
private ChanceSettingsImpl chanceSettings;
private PeriodSettingsImpl periodSettings;
private ChanceImplementation chanceImplementation;
private PeriodImplementation periodImplementation;
public RegrowthEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Restores " + PLACEHOLDER_HEAL_AMOUNT + " hearts every few seconds.");
this.getDefaults().setLevelMax(5);
this.getDefaults().setTier(0.7);
public RegrowthEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription("Restores " + GENERIC_AMOUNT + "❤ every few seconds.");
this.setMaxLevel(5);
this.setRarity(Rarity.VERY_RARE);
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this,
"20.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(100, 0, 1, 100));
this.periodImplementation = PeriodImplementation.create(this, "100");
this.periodSettings = PeriodSettingsImpl.create(config);
this.healMinHealth = EnchantScaler.read(this, "Settings.Heal.Min_Health", "0.5",
"Minimal entity health for the enchantment to have effect.");
this.healMaxHealth = EnchantScaler.read(this, "Settings.Heal.Max_Health", "20.0",
"Maximal entity health when the enchantment will not heal anymore.");
this.healAmount = EnchantScaler.read(this, "Settings.Heal.Amount", "0.25",
"Amount of hearts to be restored.");
this.minHealth = Modifier.read(config, "Settings.Heal.Min_Health",
Modifier.add(0.5, 0, 0),
"Minimal entity health for the enchantment to have effect."
);
this.addPlaceholder(PLACEHOLDER_HEAL_AMOUNT, level -> NumberUtil.format(this.getHealAmount(level)));
this.addPlaceholder(PLACEHOLDER_HEAL_MIN_HEALTH, level -> NumberUtil.format(this.getHealMaxHealth(level)));
this.addPlaceholder(PLACEHOLDER_HEAL_MAX_HEALTH, level -> NumberUtil.format(this.getHealMaxHealth(level)));
this.maxHealth = Modifier.read(config, "Settings.Heal.Max_Health",
Modifier.add(20, 0, 0),
"Maximal entity health when the enchantment will not heal anymore."
);
this.healAmount = Modifier.read(config, "Settings.Heal.Amount",
Modifier.add(0, 0.1, 1, 10),
"Amount of hearts to be restored."
);
this.addPlaceholder(GENERIC_AMOUNT, level -> NumberUtil.format(this.getHealAmount(level)));
this.addPlaceholder(GENERIC_MIN, level -> NumberUtil.format(this.getMinHealthToHeal(level)));
this.addPlaceholder(GENERIC_MAX, level -> NumberUtil.format(this.getMaxHealthToHeal(level)));
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public PeriodImplementation getPeriodImplementation() {
return periodImplementation;
public PeriodicSettings getPeriodSettings() {
return periodSettings;
}
@NotNull
@ -82,12 +91,12 @@ public class RegrowthEnchant extends ExcellentEnchant implements Chanced, Passiv
return this.healAmount.getValue(level);
}
public double getHealMinHealth(int level) {
return this.healMinHealth.getValue(level);
public double getMinHealthToHeal(int level) {
return this.minHealth.getValue(level);
}
public double getHealMaxHealth(int level) {
return this.healMaxHealth.getValue(level);
public double getMaxHealthToHeal(int level) {
return this.maxHealth.getValue(level);
}
@Override
@ -96,7 +105,7 @@ public class RegrowthEnchant extends ExcellentEnchant implements Chanced, Passiv
double healthMax = EntityUtil.getAttribute(entity, Attribute.GENERIC_MAX_HEALTH);
double healthHas = entity.getHealth();
if (healthHas < this.getHealMinHealth(level) || healthHas > this.getHealMaxHealth(level)) return false;
if (healthHas < this.getMinHealthToHeal(level) || healthHas > this.getMaxHealthToHeal(level)) return false;
if (healthHas >= healthMax) return false;
double amount = Math.min(healthMax, healthHas + this.getHealAmount(level));

View File

@ -5,51 +5,56 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.PeriodSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.NumberUtil;
public class SaturationEnchant extends ExcellentEnchant implements PassiveEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class SaturationEnchant extends AbstractEnchantmentData implements PassiveEnchant {
public static final String ID = "saturation";
private static final String PLACEHOLDER_SATURATION_AMOUNT = "%enchantment_saturation_amount%";
private static final String PLACEHOLDER_SATURATION_MAX_FOOD_LEVEL = "%enchantment_saturation_max_food_level%";
private Modifier feedAmount;
private Modifier maxFoodLevel;
private EnchantScaler saturationAmount;
private EnchantScaler saturationMaxFoodLevel;
private PeriodSettingsImpl periodSettings;
private PeriodImplementation periodImplementation;
public SaturationEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Restores " + PLACEHOLDER_SATURATION_AMOUNT + " food points every few seconds.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.5);
public SaturationEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription("Restores " + GENERIC_AMOUNT + " food points every few seconds.");
this.setMaxLevel(3);
this.setRarity(Rarity.RARE);
}
@Override
public void loadSettings() {
super.loadSettings();
this.periodImplementation = PeriodImplementation.create(this, "100");
protected void loadAdditional(@NotNull FileConfig config) {
this.periodSettings = PeriodSettingsImpl.create(config);
this.saturationAmount = EnchantScaler.read(this, "Settings.Saturation.Amount", Placeholders.ENCHANTMENT_LEVEL,
this.feedAmount = Modifier.read(config, "Settings.Saturation.Amount",
Modifier.add(0, 1, 1, 10),
"Amount of food points to restore.");
this.saturationMaxFoodLevel = EnchantScaler.read(this, "Settings.Saturation.Max_Food_Level", "20",
this.maxFoodLevel = Modifier.read(config, "Settings.Saturation.Max_Food_Level",
Modifier.add(20, 0, 0),
"Maximal player's food level for the enchantment to stop feeding them.");
this.addPlaceholder(PLACEHOLDER_SATURATION_AMOUNT, level -> NumberUtil.format(this.getSaturationAmount(level)));
this.addPlaceholder(PLACEHOLDER_SATURATION_MAX_FOOD_LEVEL, level -> NumberUtil.format(this.getMaxFoodLevel(level)));
this.addPlaceholder(GENERIC_AMOUNT, level -> NumberUtil.format(this.getFeedAmount(level)));
this.addPlaceholder(GENERIC_MAX, level -> NumberUtil.format(this.getMaxFoodLevel(level)));
}
@NotNull
@Override
public PeriodImplementation getPeriodImplementation() {
return periodImplementation;
public PeriodicSettings getPeriodSettings() {
return periodSettings;
}
@Override
@ -58,12 +63,12 @@ public class SaturationEnchant extends ExcellentEnchant implements PassiveEnchan
return EnchantmentTarget.ARMOR_HEAD;
}
public final int getSaturationAmount(int level) {
return (int) this.saturationAmount.getValue(level);
public final int getFeedAmount(int level) {
return (int) this.feedAmount.getValue(level);
}
public final int getMaxFoodLevel(int level) {
return (int) this.saturationMaxFoodLevel.getValue(level);
return (int) this.maxFoodLevel.getValue(level);
}
@Override
@ -71,7 +76,7 @@ public class SaturationEnchant extends ExcellentEnchant implements PassiveEnchan
if (!(entity instanceof Player player)) return false;
if (player.getFoodLevel() >= this.getMaxFoodLevel(level)) return false;
int amount = this.getSaturationAmount(level);
int amount = this.getFeedAmount(level);
player.setFoodLevel(Math.min(20, player.getFoodLevel() + amount));
return true;
}

View File

@ -5,45 +5,51 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.PeriodSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
public class SpeedyEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class SpeedyEnchant extends AbstractEnchantmentData implements PotionData, PassiveEnchant {
public static final String ID = "sonic";
private PotionImplementation potionImplementation;
private PeriodImplementation periodImplementation;
private PotionSettingsImpl potionSettings;
private PeriodSettingsImpl periodSettings;
public SpeedyEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.3);
public SpeedyEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription("Grants permanent " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " effect.");
this.setMaxLevel(3);
this.setRarity(Rarity.UNCOMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.SPEED, true);
this.periodImplementation = PeriodImplementation.create(this, "100");
protected void loadAdditional(@NotNull FileConfig config) {
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.SPEED, true);
this.periodSettings = PeriodSettingsImpl.create(config);
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
public PotionSettings getPotionSettings() {
return potionSettings;
}
@NotNull
@Override
public PeriodImplementation getPeriodImplementation() {
return periodImplementation;
public PeriodicSettings getPeriodSettings() {
return periodSettings;
}
@Override

View File

@ -6,40 +6,44 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.NumberUtil;
public class StoppingForceEnchant extends ExcellentEnchant implements Chanced, CombatEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class StoppingForceEnchant extends AbstractEnchantmentData implements ChanceData, CombatEnchant {
public static final String ID = "stopping_force";
public static final String PLACEHOLDER_KNOCKBACK_RESISTANCE = "%knockback_resistance%";
private ChanceSettingsImpl chanceSettings;
private Modifier knockbackModifier;
private ChanceImplementation chanceImplementation;
private EnchantScaler knockbackModifier;
public StoppingForceEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to resist knockback in combat by " + PLACEHOLDER_KNOCKBACK_RESISTANCE + "%.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.5);
public StoppingForceEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to resist knockback in combat by " + GENERIC_AMOUNT + "%.");
this.setMaxLevel(3);
this.setRarity(Rarity.UNCOMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this, "100.0");
this.knockbackModifier = EnchantScaler.read(this, "Settings.Knockback_Modifier",
"0.7 - " + Placeholders.ENCHANTMENT_LEVEL + " / 5.0",
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(100, 0, 0, 100));
this.knockbackModifier = Modifier.read(config, "Settings.Knockback_Modifier",
Modifier.add(0.9, -0.2, 1),
"Sets the knockback multiplier when taking damage.", "Lower value = less knockback.");
this.addPlaceholder(PLACEHOLDER_KNOCKBACK_RESISTANCE, level -> NumberUtil.format(this.getKnockbackModifier(level) * 100));
this.addPlaceholder(GENERIC_AMOUNT, level -> NumberUtil.format(this.getKnockbackModifier(level) * 100));
}
public double getKnockbackModifier(int level) {
@ -60,8 +64,8 @@ public class StoppingForceEnchant extends ExcellentEnchant implements Chanced, C
@NotNull
@Override
public Chanced getChanceImplementation() {
return this.chanceImplementation;
public ChanceSettings getChanceSettings() {
return this.chanceSettings;
}
@Override
@ -73,8 +77,10 @@ public class StoppingForceEnchant extends ExcellentEnchant implements Chanced, C
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.checkTriggerChance(level)) return false;
double mod = Math.max(0, this.getKnockbackModifier(level));
this.plugin.runTask(task -> {
victim.setVelocity(victim.getVelocity().multiply(this.getKnockbackModifier(level)));
victim.setVelocity(victim.getVelocity().multiply(mod));
});
return true;
}

View File

@ -0,0 +1,121 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.world.LootGenerateEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.loot.LootTable;
import org.bukkit.loot.LootTables;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.manager.SimpeListener;
import su.nightexpress.nightcore.util.StringUtil;
import su.nightexpress.nightcore.util.random.Rnd;
import java.io.File;
import java.util.*;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class TreasureHunterEnchant extends AbstractEnchantmentData implements ChanceData, GenericEnchant, SimpeListener {
public static final String ID = "treasure_hunter";
private ChanceSettingsImpl chanceSettings;
private final Set<LootTables> lootTables;
public TreasureHunterEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to get more items in loot chests.");
this.setMaxLevel(4);
this.setRarity(Rarity.RARE);
this.lootTables = new HashSet<>();
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(2.5, 2.5, 1, 100));
boolean isWhitelist = ConfigValue.create("Settings.LootTables.Whitelist",
false,
"When 'true', uses only loot tables listed below.",
"When 'false', uses ALL loot tables except ones listed below.",
"[Default is false]"
).read(config);
Set<LootTables> tables = ConfigValue.forSet("Settings.LootTables.List",
id -> StringUtil.getEnum(id, LootTables.class).orElse(null),
(cfg, path, set) -> cfg.set(path, set.stream().map(Enum::name).toList()),
Set.of(
LootTables.ENDER_DRAGON,
LootTables.END_CITY_TREASURE
),
"List of loot tables that are added or excluded (depends on Whitelist setting) for this enchantment.",
"Available loot table names: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/loot/LootTables.html"
).read(config);
if (isWhitelist) {
this.lootTables.addAll(tables);
}
else {
this.lootTables.addAll(Arrays.asList(LootTables.values()));
this.lootTables.removeAll(tables);
}
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@Override
@NotNull
public EnchantmentTarget getCategory() {
return EnchantmentTarget.ARMOR_HEAD;
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onLootExplore(LootGenerateEvent event) {
if (this.lootTables.isEmpty()) return;
if (!(event.getEntity() instanceof Player player)) return;
if (!this.isAvailableToUse(player)) return;
ItemStack helmet = player.getInventory().getHelmet();
if (helmet == null || helmet.getType().isAir()) return;
int level = EnchantUtils.getLevel(helmet, this.getEnchantment());
if (level < 1) return;
if (!this.checkTriggerChance(level)) return;
InventoryHolder holder = event.getInventoryHolder();
if (holder == null) return;
Inventory inventory = holder.getInventory();
LootTable lootTable = Rnd.get(this.lootTables).getLootTable();
Collection<ItemStack> items = lootTable.populateLoot(Rnd.RANDOM, event.getLootContext());
items.forEach(inventory::addItem);
this.consumeCharges(helmet, level);
}
}

View File

@ -0,0 +1,65 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.PeriodicSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionData;
import su.nightexpress.excellentenchants.api.enchantment.data.PotionSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.PeriodSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class WaterBreathingEnchant extends AbstractEnchantmentData implements PotionData, PassiveEnchant {
public static final String ID = "aquaman";
private PotionSettingsImpl potionSettings;
private PeriodSettingsImpl periodSettings;
public WaterBreathingEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setMaxLevel(1);
this.setRarity(Rarity.UNCOMMON);
this.setDescription("Grants permanent " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " effect.");
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.WATER_BREATHING, true);
this.periodSettings = PeriodSettingsImpl.create(config);
}
@NotNull
@Override
public PotionSettings getPotionSettings() {
return potionSettings;
}
@NotNull
@Override
public PeriodicSettings getPeriodSettings() {
return periodSettings;
}
@Override
@NotNull
public EnchantmentTarget getCategory() {
return EnchantmentTarget.ARMOR_HEAD;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
return this.addEffect(entity, level);
}
}

View File

@ -11,34 +11,39 @@ import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.NumberUtil;
public class EnchantBomber extends ExcellentEnchant implements Chanced, BowEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class BomberEnchant extends AbstractEnchantmentData implements ChanceData, BowEnchant {
public static final String ID = "bomber";
public static final String PLACEHOLDER_FUSE_TICKS = "%enchantment_fuse_ticks%";
private EnchantScaler fuseTicks;
private ChanceImplementation chanceImplementation;
private Modifier fuseTicks;
private ChanceSettingsImpl chanceSettings;
public EnchantBomber(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch TNT that explodes in " + PLACEHOLDER_FUSE_TICKS + "s.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.7);
this.getDefaults().setConflicts(
EnchantEnderBow.ID, EnchantGhast.ID,
EnchantExplosiveArrows.ID, EnchantPoisonedArrows.ID, EnchantConfusingArrows.ID,
EnchantWitheredArrows.ID, EnchantElectrifiedArrows.ID, EnchantDragonfireArrows.ID,
public BomberEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to launch TNT that explodes in " + GENERIC_TIME + "s.");
this.setMaxLevel(3);
this.setRarity(Rarity.RARE);
this.setConflicts(
EnderBowEnchant.ID, GhastEnchant.ID,
ExplosiveArrowsEnchant.ID, PoisonedArrowsEnchant.ID, ConfusingArrowsEnchant.ID,
WitheredArrowsEnchant.ID, ElectrifiedArrowsEnchant.ID, DragonfireArrowsEnchant.ID,
DarknessArrowsEnchant.ID,
EnchantHover.ID, FlareEnchant.ID,
HoverEnchant.ID, FlareEnchant.ID,
Enchantment.ARROW_FIRE.getKey().getKey(),
Enchantment.ARROW_KNOCKBACK.getKey().getKey(),
Enchantment.ARROW_DAMAGE.getKey().getKey()
@ -46,21 +51,20 @@ public class EnchantBomber extends ExcellentEnchant implements Chanced, BowEncha
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this,
"5.0 * " + Placeholders.ENCHANTMENT_LEVEL);
this.fuseTicks = EnchantScaler.read(this, "Settings.Fuse_Ticks",
"100 - " + Placeholders.ENCHANTMENT_LEVEL + " * 10",
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(3.5, 1.5, 1, 100));
this.fuseTicks = Modifier.read(config, "Settings.Fuse_Ticks",
Modifier.add(110, -10, 1),
"Sets fuse ticks (before it will explode) for the launched TNT.");
this.addPlaceholder(PLACEHOLDER_FUSE_TICKS, level -> NumberUtil.format((double) this.getFuseTicks(level) / 20D));
this.addPlaceholder(GENERIC_TIME, level -> NumberUtil.format((double) this.getFuseTicks(level) / 20D));
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
public int getFuseTicks(int level) {
@ -84,9 +88,11 @@ public class EnchantBomber extends ExcellentEnchant implements Chanced, BowEncha
if (!this.checkTriggerChance(level)) return false;
if (!(event.getProjectile() instanceof Projectile projectile)) return false;
int fuseTicks = Math.max(1, this.getFuseTicks(level));
TNTPrimed primed = projectile.getWorld().spawn(projectile.getLocation(), TNTPrimed.class);
primed.setVelocity(projectile.getVelocity().multiply(event.getForce() * 1.25));
primed.setFuseTicks(this.getFuseTicks(level));
primed.setFuseTicks(fuseTicks);
primed.setSource(shooter);
event.setProjectile(primed);
return true;

View File

@ -0,0 +1,101 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.*;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class ConfusingArrowsEnchant extends AbstractEnchantmentData implements ChanceData, ArrowData, PotionData, BowEnchant {
public static final String ID = "confusing_arrows";
private ArrowSettingsImpl arrowSettings;
private ChanceSettingsImpl chanceSettings;
private PotionSettingsImpl potionSettings;
public ConfusingArrowsEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " (" + ENCHANTMENT_POTION_DURATION + "s.)");
this.setMaxLevel(3);
this.setRarity(Rarity.COMMON);
this.setConflicts(EnderBowEnchant.ID, GhastEnchant.ID, BomberEnchant.ID);
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.of(Particle.SPELL_MOB));
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(10, 5, 1, 100));
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.CONFUSION, false,
Modifier.add(3, 3, 1, 300),
Modifier.add(0, 1, 1, 10)
);
}
@NotNull
@Override
public ArrowSettings getArrowSettings() {
return arrowSettings;
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public PotionSettings getPotionSettings() {
return potionSettings;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -12,61 +12,66 @@ import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.*;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public class DarknessArrowsEnchant extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class DarknessArrowsEnchant extends AbstractEnchantmentData implements ChanceData, ArrowData, PotionData, BowEnchant {
public static final String ID = "darkness_arrows";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
private ArrowSettingsImpl arrowSettings;
private ChanceSettingsImpl chanceSettings;
private PotionSettingsImpl potionSettings;
public DarknessArrowsEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.1);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
public DarknessArrowsEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " (" + ENCHANTMENT_POTION_DURATION + "s.)");
this.setMaxLevel(3);
this.setRarity(Rarity.COMMON);
this.setConflicts(EnderBowEnchant.ID, GhastEnchant.ID, BomberEnchant.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.ASH));
this.chanceImplementation = ChanceImplementation.create(this,
"25.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5.0");
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.DARKNESS, false,
"4.0 + " + Placeholders.ENCHANTMENT_LEVEL,
Placeholders.ENCHANTMENT_LEVEL);
protected void loadAdditional(@NotNull FileConfig config) {
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.of(Particle.ASH));
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(8, 4, 1, 100));
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.DARKNESS, false,
Modifier.add(3.5, 1.5, 1, 300),
Modifier.add(0, 1, 1, 5)
);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
public ArrowSettings getArrowSettings() {
return arrowSettings;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
public PotionSettings getPotionSettings() {
return potionSettings;
}
@NotNull
@ -81,6 +86,7 @@ public class DarknessArrowsEnchant extends ExcellentEnchant implements Chanced,
if (!this.checkTriggerChance(level)) return false;
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
return arrow.addCustomEffect(this.createEffect(level), true);
}

View File

@ -0,0 +1,168 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.*;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.LingeringPotionSplashEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.projectiles.ProjectileSource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowData;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.ItemUtil;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.Version;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class DragonfireArrowsEnchant extends AbstractEnchantmentData implements ChanceData, ArrowData, BowEnchant {
public static final String ID = "dragonfire_arrows";
private Modifier fireDuration;
private Modifier fireRadius;
private ArrowSettingsImpl arrowSettings;
private ChanceSettingsImpl chanceSettings;
public DragonfireArrowsEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to launch an dragonfire arrow (R=" + GENERIC_RADIUS + ", " + GENERIC_DURATION + "s).");
this.setMaxLevel(3);
this.setRarity(Rarity.RARE);
this.setConflicts(EnderBowEnchant.ID, GhastEnchant.ID, BomberEnchant.ID);
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.of(Particle.DRAGON_BREATH));
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(3, 3, 1, 100));
this.fireDuration = Modifier.read(config, "Settings.Fire.Duration",
Modifier.multiply(100, 1, 1, 60 * 20),
"Sets the dragonfire cloud effect duration (in ticks). 20 ticks = 1 second.");
this.fireRadius = Modifier.read(config, "Settings.Fire.Radius",
Modifier.add(1, 1, 1, 5),
"Sets the dragonfire cloud effect radius.");
this.addPlaceholder(GENERIC_DURATION, level -> NumberUtil.format(this.getFireDuration(level) / 20D));
this.addPlaceholder(GENERIC_RADIUS, level -> NumberUtil.format(this.getFireRadius(level)));
}
@NotNull
@Override
public ArrowSettings getArrowSettings() {
return arrowSettings;
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
public int getFireDuration(int level) {
return (int) this.fireDuration.getValue(level);
}
public double getFireRadius(int level) {
return this.fireRadius.getValue(level);
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (event.getHitEntity() != null) return false;
if (projectile.getShooter() == null) return false;
this.createCloud(projectile.getShooter(), projectile.getLocation(), event.getHitEntity(), event.getHitBlock(), event.getHitBlockFace(), level);
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
this.createCloud(shooter, victim.getLocation(), victim, null, null, level);
return false;
}
private void createCloud(@NotNull ProjectileSource shooter, @NotNull Location location,
@Nullable Entity hitEntity, @Nullable Block hitBlock, @Nullable BlockFace hitFace,
int level) {
World world = location.getWorld();
if (world == null) return;
// There are some tweaks to respect protection plugins by using event call.
ItemStack item = new ItemStack(Material.LINGERING_POTION);
ItemUtil.editMeta(item, meta -> {
if (meta instanceof PotionMeta potionMeta) {
potionMeta.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 20, 0), true);
}
});
ThrownPotion potion = shooter.launchProjectile(ThrownPotion.class);
potion.setItem(item);
potion.teleport(location);
AreaEffectCloud cloud = world.spawn(location, AreaEffectCloud.class);
cloud.clearCustomEffects();
cloud.setSource(shooter);
cloud.setParticle(Particle.DRAGON_BREATH);
cloud.setRadius((float) this.getFireRadius(level));
cloud.setDuration(this.getFireDuration(level));
cloud.setRadiusPerTick((7.0F - cloud.getRadius()) / (float) cloud.getDuration());
cloud.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 1, 1), true);
LingeringPotionSplashEvent splashEvent;
if (Version.isAtLeast(Version.V1_20_R3)) {
splashEvent = new LingeringPotionSplashEvent(potion, hitEntity, hitBlock, hitFace, cloud);
}
else {
splashEvent = new LingeringPotionSplashEvent(potion, cloud);
}
plugin.getPluginManager().callEvent(splashEvent);
if (splashEvent.isCancelled()) {
cloud.remove();
}
potion.remove();
}
}

View File

@ -0,0 +1,130 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowData;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.LocationUtil;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.ENCHANTMENT_CHANCE;
import static su.nightexpress.excellentenchants.Placeholders.GENERIC_DAMAGE;
public class ElectrifiedArrowsEnchant extends AbstractEnchantmentData implements ChanceData, ArrowData, BowEnchant {
public static final String ID = "electrified_arrows";
private ArrowSettingsImpl arrowSettings;
private ChanceSettingsImpl chanceSettings;
private Modifier damageModifier;
private boolean thunderstormOnly;
public ElectrifiedArrowsEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance for an arrow to strike lightning with " + GENERIC_DAMAGE + "❤ extra damage.");
this.setMaxLevel(3);
this.setRarity(Rarity.UNCOMMON);
this.setConflicts(EnderBowEnchant.ID, GhastEnchant.ID, BomberEnchant.ID);
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.of(Particle.FIREWORKS_SPARK));
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(0, 5, 1, 100));
this.thunderstormOnly = ConfigValue.create("Settings.During_Thunderstorm_Only",
false,
"Sets whether or not enchantment will have effect only during thunderstorm in the world."
).read(config);
this.damageModifier = Modifier.read(config, "Settings.Damage_Modifier",
Modifier.add(1.25, 0.25, 1, 10000),
"Sets additional damage caused by enchantment's effect."
);
this.addPlaceholder(GENERIC_DAMAGE, level -> NumberUtil.format(this.getDamage(level)));
}
@NotNull
@Override
public ArrowSettings getArrowSettings() {
return arrowSettings;
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
public boolean isDuringThunderstormOnly() {
return thunderstormOnly;
}
public double getDamage(int level) {
return this.damageModifier.getValue(level);
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
private void summonLightning(@NotNull Block block) {
Location location = block.getLocation();
block.getWorld().strikeLightningEffect(location);
if (this.hasVisualEffects()) {
Location center = LocationUtil.getCenter(location.add(0, 1, 0), false);
UniParticle.blockCrack(block.getType()).play(center, 0.5, 0.1, 100);
UniParticle.of(Particle.FIREWORKS_SPARK).play(center, 0.75, 0.05, 120);
}
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (event.getHitEntity() != null || event.getHitBlock() == null) return false;
Block block = event.getHitBlock();
this.summonLightning(block);
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
this.summonLightning(victim.getLocation().getBlock().getRelative(BlockFace.DOWN));
event.setDamage(event.getDamage() + this.getDamage(level));
return false;
}
}

View File

@ -1,96 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
public class EnchantConfusingArrows extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
public static final String ID = "confusing_arrows";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
public EnchantConfusingArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.1);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.SPELL_MOB));
this.chanceImplementation = ChanceImplementation.create(this,
"20.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5.0");
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.CONFUSION, false,
"6.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 3.0",
Placeholders.ENCHANTMENT_LEVEL);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,155 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.LingeringPotionSplashEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.projectiles.ProjectileSource;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.ItemUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantDragonfireArrows extends ExcellentEnchant implements Chanced, Arrowed, BowEnchant {
public static final String ID = "dragonfire_arrows";
public static final String PLACEHOLDER_FIRE_RADIUS = "%enchantment_fire_radius%";
public static final String PLACEHOLDER_FIRE_DURATION = "%enchantment_fire_duration%";
private EnchantScaler fireDuration;
private EnchantScaler fireRadius;
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
public EnchantDragonfireArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an dragonfire arrow (R=" + PLACEHOLDER_FIRE_RADIUS + ", " + PLACEHOLDER_FIRE_DURATION + "s).");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.7);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.DRAGON_BREATH));
this.chanceImplementation = ChanceImplementation.create(this,
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
this.fireDuration = EnchantScaler.read(this, "Settings.Fire.Duration",
"100 * " + Placeholders.ENCHANTMENT_LEVEL,
"Sets the dragonfire cloud effect duration (in ticks). 20 ticks = 1 second.");
this.fireRadius = EnchantScaler.read(this, "Settings.Fire.Radius",
"2.0 + " + Placeholders.ENCHANTMENT_LEVEL,
"Sets the dragonfire cloud effect radius.");
this.addPlaceholder(PLACEHOLDER_FIRE_DURATION, level -> NumberUtil.format(this.getFireDuration(level) / 20D));
this.addPlaceholder(PLACEHOLDER_FIRE_RADIUS, level -> NumberUtil.format(this.getFireRadius(level)));
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
public int getFireDuration(int level) {
return (int) this.fireDuration.getValue(level);
}
public double getFireRadius(int level) {
return this.fireRadius.getValue(level);
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (!this.isOurProjectile(projectile)) return false;
if (event.getHitEntity() != null) return false;
if (projectile.getShooter() == null) return false;
this.createCloud(projectile.getShooter(), projectile.getLocation() , level);
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isOurProjectile(projectile)) return false;
this.createCloud(shooter, victim.getLocation(), level);
return false;
}
private void createCloud(@NotNull ProjectileSource shooter, @NotNull Location location, int level) {
World world = location.getWorld();
if (world == null) return;
// There are some tweaks to respect protection plugins using even call.
ItemStack item = new ItemStack(Material.LINGERING_POTION);
ItemUtil.mapMeta(item, meta -> {
if (meta instanceof PotionMeta potionMeta) {
potionMeta.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 20, 0), true);
}
});
ThrownPotion potion = shooter.launchProjectile(ThrownPotion.class);
potion.setItem(item);
potion.teleport(location);
AreaEffectCloud cloud = world.spawn(location, AreaEffectCloud.class);
cloud.clearCustomEffects();
cloud.setSource(shooter);
cloud.setParticle(Particle.DRAGON_BREATH);
cloud.setRadius((float) this.getFireRadius(level));
cloud.setDuration(this.getFireDuration(level));
cloud.setRadiusPerTick((7.0F - cloud.getRadius()) / (float) cloud.getDuration());
cloud.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 1, 1), true);
LingeringPotionSplashEvent splashEvent = new LingeringPotionSplashEvent(potion, cloud);
plugin.getPluginManager().callEvent(splashEvent);
if (splashEvent.isCancelled()) {
cloud.remove();
}
potion.remove();
}
}

View File

@ -1,114 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.block.Block;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Item;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.LocationUtil;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantElectrifiedArrows extends ExcellentEnchant implements Chanced, Arrowed, BowEnchant {
public static final String ID = "electrified_arrows";
private static final String META_NO_ITEM_DAMAGE = "itemNoDamage";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
public EnchantElectrifiedArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an electrified arrow.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.3);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.FIREWORKS_SPARK));
this.chanceImplementation = ChanceImplementation.create(this,
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (!this.isOurProjectile(projectile)) return false;
if (event.getHitEntity() != null || event.getHitBlock() == null) return false;
Block block = event.getHitBlock();
block.getWorld().strikeLightning(block.getLocation()).setMetadata(META_NO_ITEM_DAMAGE, new FixedMetadataValue(plugin, true));
if (this.hasVisualEffects()) {
Location center = LocationUtil.getCenter(block.getLocation());
UniParticle.blockCrack(block.getType()).play(center, 1, 0.05, 120);
UniParticle.of(Particle.FIREWORKS_SPARK).play(center, 1, 0.05, 120);
}
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isOurProjectile(projectile)) return false;
plugin.getServer().getScheduler().runTask(plugin, () -> {
if (victim.isDead()) return;
victim.setNoDamageTicks(0);
victim.getWorld().strikeLightning(victim.getLocation()).setMetadata(META_NO_ITEM_DAMAGE, new FixedMetadataValue(plugin, true));
});
return false;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemDamage(EntityDamageByEntityEvent e) {
if (!e.getDamager().hasMetadata(META_NO_ITEM_DAMAGE)) return;
if (e.getEntity() instanceof Item || e.getEntity() instanceof ItemFrame) {
e.setCancelled(true);
e.getEntity().setFireTicks(0);
}
}
}

View File

@ -1,137 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantExplosiveArrows extends ExcellentEnchant implements Chanced, Arrowed, BowEnchant {
public static final String ID = "explosive_arrows";
public static final String PLACEHOLDER_EXPLOSION_POWER = "%enchantment_explosion_power%";
private boolean explosionFireSpread;
private boolean explosionDamageItems;
private boolean explosionDamageBlocks;
private EnchantScaler explosionSize;
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
private Entity lastExploder;
public EnchantExplosiveArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an explosive arrow.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.7);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.SMOKE_NORMAL));
this.chanceImplementation = ChanceImplementation.create(this,
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
this.explosionFireSpread = JOption.create("Settings.Explosion.Fire_Spread", true,
"When 'true' creates fire on nearby blocks.").read(cfg);
this.explosionDamageItems = JOption.create("Settings.Explosion.Damage_Items", false,
"When 'true' inflicts damage to items on the ground.").read(cfg);
this.explosionDamageBlocks = JOption.create("Settings.Explosion.Damage_Blocks", false,
"When 'true' allows to break blocks by explosion.").read(cfg);
this.explosionSize = EnchantScaler.read(this, "Settings.Explosion.Size",
"2.0 + " + Placeholders.ENCHANTMENT_LEVEL,
"Sets the explosion size. The more size - the bigger explosion.");
this.addPlaceholder(PLACEHOLDER_EXPLOSION_POWER, level -> NumberUtil.format(this.getExplosionSize(level)));
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
public final double getExplosionSize(int level) {
return this.explosionSize.getValue(level);
}
public final boolean isExplosionFireSpread() {
return this.explosionFireSpread;
}
public final boolean isExplosionDamageBlocks() {
return this.explosionDamageBlocks;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (!this.isOurProjectile(projectile)) return false;
if (projectile.getShooter() instanceof Entity entity) {
this.lastExploder = entity;
}
World world = projectile.getWorld();
float explSize = (float) this.getExplosionSize(level);
boolean explFire = this.isExplosionFireSpread();
boolean explBlocks = this.isExplosionDamageBlocks();
boolean exploded = world.createExplosion(projectile.getLocation(), explSize, explFire, explBlocks, this.lastExploder);
this.lastExploder = null;
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemDamage(EntityDamageByEntityEvent event) {
if (event.getCause() != EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) return;
if (this.explosionDamageItems) return;
if (this.lastExploder == null || this.lastExploder != event.getDamager()) return;
if (event.getEntity() instanceof Item || event.getEntity() instanceof ItemFrame) {
event.setCancelled(true);
}
}
}

View File

@ -1,96 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
public class EnchantHover extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
public static final String ID = "hover";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
public EnchantHover(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.1);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.BUBBLE_POP));
this.chanceImplementation = ChanceImplementation.create(this,
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.LEVITATION, false,
"2.5 + " + Placeholders.ENCHANTMENT_LEVEL,
Placeholders.ENCHANTMENT_LEVEL);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,96 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
public class EnchantPoisonedArrows extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
public static final String ID = "poisoned_arrows";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
public EnchantPoisonedArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.1);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.SLIME));
this.chanceImplementation = ChanceImplementation.create(this,
"25.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.POISON, false,
"2.5 + " + Placeholders.ENCHANTMENT_LEVEL,
Placeholders.ENCHANTMENT_LEVEL);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,96 +0,0 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
public class EnchantWitheredArrows extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
public static final String ID = "withered_arrows";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
private PotionImplementation potionImplementation;
public EnchantWitheredArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.5);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.SPELL_WITCH));
this.chanceImplementation = ChanceImplementation.create(this,
"15.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5.0");
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.WITHER, false,
"2.5 + " + Placeholders.ENCHANTMENT_LEVEL + " * 0.75",
Placeholders.ENCHANTMENT_LEVEL);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public PotionImplementation getPotionImplementation() {
return potionImplementation;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -11,30 +11,35 @@ import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
public class EnchantEnderBow extends ExcellentEnchant implements BowEnchant, Chanced {
import java.io.File;
public class EnderBowEnchant extends AbstractEnchantmentData implements ChanceData, BowEnchant {
public static final String ID = "ender_bow";
private ChanceImplementation chanceImplementation;
private ChanceSettingsImpl chanceSettings;
public EnchantEnderBow(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Shoots ender pearls instead of arrows.");
this.getDefaults().setLevelMax(1);
this.getDefaults().setTier(1.0);
public EnderBowEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription("Shoots ender pearls instead of arrows.");
this.setMaxLevel(1);
this.setRarity(Rarity.VERY_RARE);
this.getDefaults().setConflicts(
EnchantBomber.ID, EnchantGhast.ID,
EnchantExplosiveArrows.ID, EnchantPoisonedArrows.ID, EnchantConfusingArrows.ID,
EnchantWitheredArrows.ID, EnchantElectrifiedArrows.ID, EnchantDragonfireArrows.ID,
this.setConflicts(
BomberEnchant.ID, GhastEnchant.ID,
ExplosiveArrowsEnchant.ID, PoisonedArrowsEnchant.ID, ConfusingArrowsEnchant.ID,
WitheredArrowsEnchant.ID, ElectrifiedArrowsEnchant.ID, DragonfireArrowsEnchant.ID,
DarknessArrowsEnchant.ID, VampiricArrowsEnchant.ID,
EnchantHover.ID, FlareEnchant.ID,
HoverEnchant.ID, FlareEnchant.ID,
Enchantment.ARROW_FIRE.getKey().getKey(),
Enchantment.ARROW_KNOCKBACK.getKey().getKey(),
Enchantment.ARROW_DAMAGE.getKey().getKey()
@ -42,15 +47,14 @@ public class EnchantEnderBow extends ExcellentEnchant implements BowEnchant, Cha
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this, "100");
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@Override

View File

@ -0,0 +1,148 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowData;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.manager.SimpeListener;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class ExplosiveArrowsEnchant extends AbstractEnchantmentData implements ChanceData, ArrowData, BowEnchant, SimpeListener {
public static final String ID = "explosive_arrows";
private boolean explosionFireSpread;
private boolean explosionDamageItems;
private boolean explosionDamageBlocks;
private Modifier explosionSize;
private ArrowSettingsImpl arrowSettings;
private ChanceSettingsImpl chanceSettings;
private Entity lastExploder;
public ExplosiveArrowsEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to launch an explosive arrow.");
this.setMaxLevel(3);
this.setRarity(Rarity.RARE);
this.setConflicts(EnderBowEnchant.ID, GhastEnchant.ID, BomberEnchant.ID);
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.of(Particle.SMOKE_NORMAL));
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(3, 2, 1, 100));
this.explosionFireSpread = ConfigValue.create("Settings.Explosion.Fire_Spread",
true,
"When 'true' creates fire on nearby blocks.").read(config);
this.explosionDamageItems = ConfigValue.create("Settings.Explosion.Damage_Items",
false,
"When 'true' inflicts damage to items on the ground.").read(config);
this.explosionDamageBlocks = ConfigValue.create("Settings.Explosion.Damage_Blocks",
false,
"When 'true' allows to break blocks by explosion.").read(config);
this.explosionSize = Modifier.read(config, "Settings.Explosion.Size",
Modifier.add(1, 1, 1, 5),
"Sets the explosion size. The more size - the bigger explosion.");
this.addPlaceholder(GENERIC_RADIUS, level -> NumberUtil.format(this.getExplosionSize(level)));
}
@NotNull
@Override
public ArrowSettings getArrowSettings() {
return arrowSettings;
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
public final double getExplosionSize(int level) {
return this.explosionSize.getValue(level);
}
public final boolean isExplosionFireSpread() {
return this.explosionFireSpread;
}
public final boolean isExplosionDamageBlocks() {
return this.explosionDamageBlocks;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (projectile.getShooter() instanceof Entity entity) {
this.lastExploder = entity;
}
World world = projectile.getWorld();
float explSize = (float) this.getExplosionSize(level);
boolean explFire = this.isExplosionFireSpread();
boolean explBlocks = this.isExplosionDamageBlocks();
/*boolean exploded = */world.createExplosion(projectile.getLocation(), explSize, explFire, explBlocks, this.lastExploder);
this.lastExploder = null;
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemDamage(EntityDamageByEntityEvent event) {
if (event.getCause() != EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) return;
if (this.explosionDamageItems) return;
if (this.lastExploder == null || this.lastExploder != event.getDamager()) return;
if (event.getEntity() instanceof Item || event.getEntity() instanceof ItemFrame) {
event.setCancelled(true);
}
}
}

View File

@ -18,36 +18,42 @@ import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowData;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public class FlareEnchant extends ExcellentEnchant implements Chanced, Arrowed, BowEnchant {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class FlareEnchant extends AbstractEnchantmentData implements ChanceData, ArrowData, BowEnchant {
public static final String ID = "flare";
private ChanceImplementation chanceImplementation;
private ArrowImplementation arrowImplementation;
private ChanceSettingsImpl chanceSettings;
private ArrowSettingsImpl arrowSettings;
public FlareEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
public FlareEnchant(@NotNull ExcellentEnchantsPlugin plugin, File file) {
super(plugin, file);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to create a torch where arrow lands.");
this.getDefaults().setLevelMax(1);
this.getDefaults().setTier(0.4);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to create a torch where arrow lands.");
this.setMaxLevel(1);
this.setRarity(Rarity.RARE);
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this, "100.0");
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.FIREWORKS_SPARK));
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config);
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.of(Particle.FIREWORKS_SPARK));
}
@NotNull
@ -64,40 +70,38 @@ public class FlareEnchant extends ExcellentEnchant implements Chanced, Arrowed,
@NotNull
@Override
public Chanced getChanceImplementation() {
return this.chanceImplementation;
public ChanceSettings getChanceSettings() {
return this.chanceSettings;
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return this.arrowImplementation;
public ArrowSettings getArrowSettings() {
return this.arrowSettings;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!(event.getProjectile() instanceof Arrow)) return false;
this.addData(arrow);
return true;
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
Block block = e.getHitBlock();
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
Block block = event.getHitBlock();
if (block == null) return false;
BlockFace face = e.getHitBlockFace();
BlockFace face = event.getHitBlockFace();
if (face == null || face == BlockFace.DOWN) return false;
Block relative = block.getRelative(face);
if (!relative.getType().isAir()) return false;
if (projectile.getShooter() instanceof Player player) {
BlockPlaceEvent event = new BlockPlaceEvent(relative, relative.getState(), block, new ItemStack(Material.TORCH), player,true, EquipmentSlot.HAND);
plugin.getPluginManager().callEvent(event);
if (event.isCancelled() || !event.canBuild()) return false;
BlockPlaceEvent placeEvent = new BlockPlaceEvent(relative, relative.getState(), block, new ItemStack(Material.TORCH), player,true, EquipmentSlot.HAND);
plugin.getPluginManager().callEvent(placeEvent);
if (placeEvent.isCancelled() || !placeEvent.canBuild()) return false;
}
if (face == BlockFace.UP) {

View File

@ -12,36 +12,40 @@ import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import su.nightexpress.nightcore.config.ConfigValue;
import su.nightexpress.nightcore.config.FileConfig;
public class EnchantGhast extends ExcellentEnchant implements BowEnchant, Chanced {
import java.io.File;
public class GhastEnchant extends AbstractEnchantmentData implements ChanceData, BowEnchant {
public static final String ID = "ghast";
private boolean fireSpread;
private EnchantScaler yield;
private ChanceImplementation chanceImplementation;
private boolean fireSpread;
private Modifier yield;
private ChanceSettingsImpl chanceSettings;
public EnchantGhast(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Shoots fireballs instead of arrows.");
this.getDefaults().setLevelMax(1);
this.getDefaults().setTier(0.3);
public GhastEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription("Shoots fireballs instead of arrows.");
this.setMaxLevel(1);
this.setRarity(Rarity.UNCOMMON);
this.getDefaults().setConflicts(
EnchantEnderBow.ID, EnchantBomber.ID,
EnchantExplosiveArrows.ID, EnchantPoisonedArrows.ID, EnchantConfusingArrows.ID,
EnchantWitheredArrows.ID, EnchantElectrifiedArrows.ID, EnchantDragonfireArrows.ID,
this.setConflicts(
EnderBowEnchant.ID, BomberEnchant.ID,
ExplosiveArrowsEnchant.ID, PoisonedArrowsEnchant.ID, ConfusingArrowsEnchant.ID,
WitheredArrowsEnchant.ID, ElectrifiedArrowsEnchant.ID, DragonfireArrowsEnchant.ID,
DarknessArrowsEnchant.ID, VampiricArrowsEnchant.ID,
EnchantHover.ID, FlareEnchant.ID,
HoverEnchant.ID, FlareEnchant.ID,
Enchantment.ARROW_FIRE.getKey().getKey(),
Enchantment.ARROW_KNOCKBACK.getKey().getKey(),
Enchantment.ARROW_DAMAGE.getKey().getKey()
@ -49,19 +53,22 @@ public class EnchantGhast extends ExcellentEnchant implements BowEnchant, Chance
}
@Override
public void loadSettings() {
super.loadSettings();
this.chanceImplementation = ChanceImplementation.create(this, "100");
this.fireSpread = JOption.create("Settings.Fire_Spread", true,
"When 'true' creates fire on nearby blocks.").read(cfg);
this.yield = EnchantScaler.read(this, "Settings.Yield", "1.0 + " + Placeholders.ENCHANTMENT_LEVEL,
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config);
this.fireSpread = ConfigValue.create("Settings.Fire_Spread",
true,
"When 'true' creates fire on nearby blocks.").read(config);
this.yield = Modifier.read(config, "Settings.Yield",
Modifier.add(2, 0, 1, 5),
"Fireball explosion size/radius. The more value = the bigger the explosion.");
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
public boolean isFireSpread() {

View File

@ -0,0 +1,101 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.*;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class HoverEnchant extends AbstractEnchantmentData implements ChanceData, ArrowData, PotionData, BowEnchant {
public static final String ID = "hover";
private ArrowSettingsImpl arrowSettings;
private ChanceSettingsImpl chanceSettings;
private PotionSettingsImpl potionSettings;
public HoverEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " (" + ENCHANTMENT_POTION_DURATION + "s.)");
this.setMaxLevel(3);
this.setRarity(Rarity.COMMON);
this.setConflicts(EnderBowEnchant.ID, GhastEnchant.ID, BomberEnchant.ID);
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.of(Particle.BUBBLE_POP));
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(3, 3, 1, 100));
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.LEVITATION, false,
Modifier.add(2, 1, 1, 15),
Modifier.add(0, 1, 1, 5)
);
}
@NotNull
@Override
public ArrowSettings getArrowSettings() {
return arrowSettings;
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public PotionSettingsImpl getPotionSettings() {
return potionSettings;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,101 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.*;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.PotionSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class PoisonedArrowsEnchant extends AbstractEnchantmentData implements ChanceData, ArrowData, PotionData, BowEnchant {
public static final String ID = "poisoned_arrows";
private ArrowSettingsImpl arrowSettings;
private ChanceSettingsImpl chanceSettings;
private PotionSettingsImpl potionSettings;
public PoisonedArrowsEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + ENCHANTMENT_POTION_TYPE + " " + ENCHANTMENT_POTION_LEVEL + " (" + ENCHANTMENT_POTION_DURATION + "s.)");
this.setMaxLevel(3);
this.setRarity(Rarity.COMMON);
this.setConflicts(EnderBowEnchant.ID, GhastEnchant.ID, BomberEnchant.ID);
}
@Override
protected void loadAdditional(@NotNull FileConfig config) {
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.of(Particle.SLIME));
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(7.5, 2.5, 1, 100));
this.potionSettings = PotionSettingsImpl.create(this, config, PotionEffectType.POISON, false,
Modifier.add(3, 1, 1, 300),
Modifier.add(0, 1, 1, 5)
);
}
@NotNull
@Override
public ArrowSettings getArrowSettings() {
return arrowSettings;
}
@NotNull
@Override
public ChanceSettings getChanceSettings() {
return chanceSettings;
}
@NotNull
@Override
public PotionSettings getPotionSettings() {
return potionSettings;
}
@NotNull
@Override
public EnchantmentTarget getCategory() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -11,47 +11,51 @@ import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.NumberUtil;
public class SniperEnchant extends ExcellentEnchant implements BowEnchant, Chanced {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class SniperEnchant extends AbstractEnchantmentData implements BowEnchant, ChanceData {
public static final String ID = "sniper";
private static final String PLACEHOLDER_PROJECTILE_SPEED = "%enchantment_projectile_speed%";
private ChanceSettingsImpl chanceSettings;
private Modifier speedModifier;
private ChanceImplementation chanceImplementation;
private EnchantScaler speedModifier;
public SniperEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
public SniperEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription("Increases projectile speed by " + PLACEHOLDER_PROJECTILE_SPEED + "%");
this.getDefaults().setLevelMax(5);
this.getDefaults().setTier(0.3);
this.setDescription("Increases projectile speed by " + GENERIC_AMOUNT + "%");
this.setMaxLevel(5);
this.setRarity(Rarity.UNCOMMON);
}
@Override
public void loadSettings() {
super.loadSettings();
protected void loadAdditional(@NotNull FileConfig config) {
this.chanceSettings = ChanceSettingsImpl.create(config);
this.chanceImplementation = ChanceImplementation.create(this, "100.0");
this.speedModifier = EnchantScaler.read(this, "Settings.Speed_Modifier",
"1.0 + " + Placeholders.ENCHANTMENT_LEVEL + " / 5.0", "Sets projectile's speed modifier.");
this.speedModifier = Modifier.read(config, "Settings.Speed_Modifier",
Modifier.add(1, 0.2, 1, 3D),
"Sets projectile's speed modifier.");
this.addPlaceholder(PLACEHOLDER_PROJECTILE_SPEED, level -> NumberUtil.format(this.getSpeedModifier(level) * 100D));
this.addPlaceholder(GENERIC_AMOUNT, level -> NumberUtil.format(this.getSpeedModifier(level) * 100D));
}
@NotNull
@Override
public Chanced getChanceImplementation() {
return this.chanceImplementation;
public ChanceSettings getChanceSettings() {
return this.chanceSettings;
}
public double getSpeedModifier(int level) {

View File

@ -14,50 +14,54 @@ import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.EntityUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.values.UniParticle;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.ExcellentEnchantsPlugin;
import su.nightexpress.excellentenchants.api.Modifier;
import su.nightexpress.excellentenchants.api.enchantment.Rarity;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowData;
import su.nightexpress.excellentenchants.api.enchantment.data.ArrowSettings;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceData;
import su.nightexpress.excellentenchants.api.enchantment.data.ChanceSettings;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.data.AbstractEnchantmentData;
import su.nightexpress.excellentenchants.enchantment.data.ArrowSettingsImpl;
import su.nightexpress.excellentenchants.enchantment.data.ChanceSettingsImpl;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.util.EntityUtil;
import su.nightexpress.nightcore.util.NumberUtil;
import su.nightexpress.nightcore.util.wrapper.UniParticle;
public class VampiricArrowsEnchant extends ExcellentEnchant implements BowEnchant, Arrowed, Chanced {
import java.io.File;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class VampiricArrowsEnchant extends AbstractEnchantmentData implements BowEnchant, ArrowData, ChanceData {
public static final String ID = "vampiric_arrows";
public static final String PLACEHOLDER_HEAL_AMOUNT = "%heal_amount%";
private ArrowSettingsImpl arrowSettings;
private ChanceSettingsImpl chanceSettings;
private Modifier healAmount;
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
private EnchantScaler healAmount;
public VampiricArrowsEnchant(@NotNull ExcellentEnchants plugin) {
super(plugin, ID);
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to restore " + PLACEHOLDER_HEAL_AMOUNT + "❤ on arrow hit.");
this.getDefaults().setLevelMax(3);
this.getDefaults().setTier(0.3);
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
public VampiricArrowsEnchant(@NotNull ExcellentEnchantsPlugin plugin, @NotNull File file) {
super(plugin, file);
this.setDescription(ENCHANTMENT_CHANCE + "% chance to restore " + GENERIC_AMOUNT + "❤ on arrow hit.");
this.setMaxLevel(3);
this.setRarity(Rarity.RARE);
this.setConflicts(EnderBowEnchant.ID, GhastEnchant.ID, BomberEnchant.ID);
}
@Override
public void loadSettings() {
super.loadSettings();
protected void loadAdditional(@NotNull FileConfig config) {
this.arrowSettings = ArrowSettingsImpl.create(config, UniParticle.redstone(Color.RED, 1f));
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.redstone(Color.RED, 1f));
this.chanceSettings = ChanceSettingsImpl.create(config, Modifier.add(8, 4, 1, 100));
this.chanceImplementation = ChanceImplementation.create(this, "20.0 * " + Placeholders.ENCHANTMENT_LEVEL);
this.healAmount = Modifier.read(config, "Settings.Heal_Amount",
Modifier.add(0, 1, 1, 10),
"Amount of health to be restored on hit."
);
this.healAmount = EnchantScaler.read(this, "Settings.Heal_Amount",
Placeholders.ENCHANTMENT_LEVEL,
"Amount of health to be restored on hit.");
this.addPlaceholder(PLACEHOLDER_HEAL_AMOUNT, level -> NumberUtil.format(this.getHealAmount(level)));
this.addPlaceholder(GENERIC_AMOUNT, level -> NumberUtil.format(this.getHealAmount(level)));
}
@NotNull
@ -68,14 +72,14 @@ public class VampiricArrowsEnchant extends ExcellentEnchant implements BowEnchan
@NotNull
@Override
public Arrowed getArrowImplementation() {
return this.arrowImplementation;
public ArrowSettings getArrowSettings() {
return this.arrowSettings;
}
@NotNull
@Override
public Chanced getChanceImplementation() {
return this.chanceImplementation;
public ChanceSettings getChanceSettings() {
return this.chanceSettings;
}
public double getHealAmount(int level) {
@ -90,11 +94,9 @@ public class VampiricArrowsEnchant extends ExcellentEnchant implements BowEnchan
@Override
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!(event.getProjectile() instanceof Arrow)) return false;
this.addData(arrow);
return true;
return this.checkTriggerChance(level);
}
@Override

Some files were not shown because too many files have changed in this diff Show More