This commit is contained in:
nulli0n 2023-01-21 04:19:57 +06:00
parent 6435834698
commit 046c11924f
236 changed files with 5808 additions and 10157 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ExcellentEnchants</artifactId>
<groupId>su.nightexpress.excellentenchants</groupId>
<version>3.2.13</version>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -45,27 +45,27 @@
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>NMS</artifactId>
<version>3.2.13</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_17_R1</artifactId>
<version>3.2.13</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_18_R2</artifactId>
<version>3.2.13</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_19_R1</artifactId>
<version>3.2.13</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>su.nightexpress.excellentenchants</groupId>
<artifactId>V1_19_R2</artifactId>
<version>3.2.13</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>fr.neatmonster</groupId>

View File

@ -1,6 +1,5 @@
package su.nightexpress.excellentenchants;
import org.bukkit.enchantments.EnchantmentTarget;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.NexPlugin;
import su.nexmedia.engine.Version;
@ -13,14 +12,16 @@ import su.nightexpress.excellentenchants.command.ListCommand;
import su.nightexpress.excellentenchants.command.TierbookCommand;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.hook.ProtocolHook;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import su.nightexpress.excellentenchants.hook.HookId;
import su.nightexpress.excellentenchants.hook.impl.ProtocolHook;
import su.nightexpress.excellentenchants.nms.EnchantNMS;
import su.nightexpress.excellentenchants.nms.v1_17_R1.V1_17_R1;
import su.nightexpress.excellentenchants.nms.v1_18_R2.V1_18_R2;
import su.nightexpress.excellentenchants.nms.v1_19_R1.V1_19_R1;
import su.nightexpress.excellentenchants.nms.v1_19_R2.V1_19_R2;
import su.nightexpress.excellentenchants.tier.TierManager;
public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
@ -28,6 +29,7 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
private EnchantNMS enchantNMS;
private EnchantManager enchantManager;
private TierManager tierManager;
@Override
@NotNull
@ -43,6 +45,9 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
return;
}
this.tierManager = new TierManager(this);
this.tierManager.setup();
this.enchantManager = new EnchantManager(this);
this.enchantManager.setup();
}
@ -53,6 +58,10 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
this.enchantManager.shutdown();
this.enchantManager = null;
}
if (this.tierManager != null) {
this.tierManager.shutdown();
this.tierManager = null;
}
}
private boolean setNMS() {
@ -67,13 +76,12 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
@Override
public void loadConfig() {
Config.load(this);
this.getConfig().initializeOptions(Config.class);
}
@Override
public void loadLang() {
this.getLangManager().loadMissing(Lang.class);
this.getLangManager().setupEnum(EnchantmentTarget.class);
this.getLangManager().setupEnum(FitItemType.class);
this.getLang().saveChanges();
}
@ -84,22 +92,27 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
mainCommand.addChildren(new EnchantCommand(this));
mainCommand.addChildren(new ListCommand(this));
mainCommand.addChildren(new TierbookCommand(this));
mainCommand.addChildren(new ReloadSubCommand<>(this, Perms.PREFIX + "admin"));
mainCommand.addChildren(new ReloadSubCommand<>(this, Perms.COMMAND_RELOAD));
}
@Override
public void registerHooks() {
if (Hooks.hasPlugin("ProtocolLib")) {
if (Hooks.hasPlugin(HookId.PROTOCOL_LIB)) {
ProtocolHook.setup();
}
else {
this.warn("ProtocolLib is not installed. Enchantments won't be displayed on items.");
this.warn(HookId.PROTOCOL_LIB + " is not installed. Enchantments won't be displayed on items.");
}
}
@Override
public void registerPermissions() {
// TODO
this.registerPermissions(Perms.class);
}
@NotNull
public TierManager getTierManager() {
return tierManager;
}
@NotNull

View File

@ -1,6 +1,20 @@
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,15 +1,25 @@
package su.nightexpress.excellentenchants;
import org.bukkit.permissions.PermissionDefault;
import su.nexmedia.engine.api.server.JPermission;
public class Perms {
public static final String PREFIX = "excellentenchants.";
private static final String PREFIX = "excellentenchants.";
private static final String PREFIX_COMMAND = PREFIX + "command.";
//public static final String ADMIN = PREFIX + "admin";
//public static final String USER = PREFIX + "user";
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 String COMMAND_BOOK = PREFIX + "command.book";
public static final String COMMAND_ENCHANT = PREFIX + "command.enchant";
public static final String COMMAND_LIST = PREFIX + "command.list";
public static final String COMMAND_TIERBOOK = PREFIX + "command.tierbook";
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.");
static {
PLUGIN.addChildren(COMMAND);
COMMAND.addChildren(COMMAND_BOOK, COMMAND_ENCHANT, COMMAND_LIST, COMMAND_RELOAD, COMMAND_TIERBOOK);
}
}

View File

@ -2,9 +2,15 @@ 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 static final String URL_PLACEHOLDERS = URL_WIKI + "Internal-Placeholders";
public static final String URL_ENGINE_SCALE = "https://github.com/nulli0n/NexEngine-spigot/wiki/Configuration-Tips#scalable-sections";
public static final String URL_WIKI = "https://github.com/nulli0n/ExcellentEnchants-spigot/wiki/";
public static final String URL_PLACEHOLDERS = URL_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_AMOUNT = "%amount%";
public static final String GENERIC_DESCRIPTION = "%description%";
public static final String GENERIC_ENCHANT = "%enchant%";
public static final String ENCHANTMENT_NAME = "%enchantment_name%";
public static final String ENCHANTMENT_NAME_FORMATTED = "%enchantment_name_formatted%";
@ -12,8 +18,6 @@ public class Placeholders extends su.nexmedia.engine.utils.Placeholders {
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_CONFLICTS = "%enchantment_conflicts%";
public static final String ENCHANTMENT_TARGET = "%enchantment_target%";
public static final String ENCHANTMENT_TIER = "%enchantment_tier%";
public static final String ENCHANTMENT_FIT_ITEM_TYPES = "%enchantment_fit_item_types%";
public static final String ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING = "%enchantment_obtain_chance_enchanting%";
@ -21,5 +25,11 @@ public class Placeholders extends su.nexmedia.engine.utils.Placeholders {
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_COST_ITEM = "%enchantment_cost_item%";
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%";
}

View File

@ -2,237 +2,211 @@ package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
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.api.manager.IListener;
import su.nexmedia.engine.lang.LangManager;
import su.nexmedia.engine.utils.*;
import su.nexmedia.engine.utils.ItemUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nexmedia.engine.utils.StringUtil;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.manager.object.EnchantTier;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.manager.type.ObtainType;
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.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.tier.Tier;
import java.util.*;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public abstract class ExcellentEnchant extends Enchantment implements IListener {
public abstract class ExcellentEnchant extends Enchantment implements IEnchantment, IListener {
protected final ExcellentEnchants plugin;
protected final JYML cfg;
protected final String id;
protected final EnchantPriority priority;
protected final EnchantPriority priority;
protected String displayName;
protected EnchantTier tier;
protected Tier tier;
protected List<String> description;
protected boolean isTreasure;
protected int levelMin;
protected int levelMax;
protected Scaler levelByEnchantCost;
protected Scaler anvilMergeCost;
protected Map<ObtainType, Double> obtainChance;
protected Set<String> conflicts;
protected Map<ObtainType, int[]> obtainLevelCap;
protected boolean hasVisualEffects;
private final Set<Enchantment> conflicts;
protected boolean isTreasure;
protected int levelMin;
protected int levelMax;
protected Scaler levelByEnchantCost;
protected Scaler anvilMergeCost;
protected Map<ObtainType, Double> obtainChance;
protected Map<ObtainType, Pair<Integer, Integer>> obtainLevelCap;
protected ItemStack costItem;
protected boolean costEnabled;
protected boolean chargesEnabled;
protected boolean chargesCustomFuel;
protected EnchantScaler chargesMax;
protected EnchantScaler chargesConsumeAmount;
protected EnchantScaler chargesRechargeAmount;
protected ItemStack chargesFuel;
protected final NamespacedKey chargesKey;
public ExcellentEnchant(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg, @NotNull EnchantPriority priority) {
super(NamespacedKey.minecraft(cfg.getFile().getName().replace(".yml", "").toLowerCase()));
public ExcellentEnchant(@NotNull ExcellentEnchants plugin, @NotNull String id, @NotNull EnchantPriority priority) {
super(NamespacedKey.minecraft(id.toLowerCase()));
this.plugin = plugin;
this.id = this.getKey().getKey();
this.cfg = cfg;
this.updateConfig();
this.cfg.saveChanges();
this.cfg = JYML.loadOrExtract(plugin, "/enchants/" + id + ".yml");
this.priority = priority;
this.conflicts = new HashSet<>();
this.loadConfig();
this.chargesKey = new NamespacedKey(plugin, this.getId() + ".charges");
}
public void loadConfig() {
this.cfg.reload();
this.displayName = StringUtil.color(cfg.getString("Name", this.getId()));
this.tier = EnchantManager.getTierById(cfg.getString("Tier", Placeholders.DEFAULT));
this.displayName = JOption.create("Name", StringUtil.capitalizeFully(this.getId().replace("_", " ")),
"Enchantment display name. It will be shown in item lore.").read(cfg);
this.tier = plugin.getTierManager().getTierById(JOption.create("Tier", Placeholders.DEFAULT,
"Enchantment tier. Must be a valid tier identifier from the 'tiers.yml'.").read(cfg));
if (this.tier == null) {
throw new IllegalStateException("Invalid tier provided for the '" + id + "' enchantment!");
this.tier = Tier.DEFAULT;
}
this.tier.getEnchants().add(this);
this.description = StringUtil.color(cfg.getStringList("Description"));
this.isTreasure = cfg.getBoolean("Is_Treasure");
this.levelMin = cfg.getInt("Level.Min");
this.levelMax = cfg.getInt("Level.Max");
this.levelByEnchantCost = new EnchantScaler(this, ObtainType.ENCHANTING.getPathName() + ".Level_By_Exp_Cost");
this.anvilMergeCost = new EnchantScaler(this, "Anvil.Merge_Cost");
this.description = JOption.create("Description", new ArrayList<>(),
"Enchantment description. It will be shown in item lore under enchantment name.",
"You can use 'Enchantment' placeholders: " + Placeholders.URL_PLACEHOLDERS).read(cfg);
this.isTreasure = JOption.create("Is_Treasure", false,
"Sets whether this enchantment is a treasure enchantment.",
"Treasure enchantments can only be received via looting, trading, or fishing.").read(cfg);
this.levelMin = Math.max(1, JOption.create("Level.Min", 1,
"Sets the minimal (start) enchantment level. Can not be less than 1.").read(cfg));
this.levelMax = JOption.create("Level.Max", 3,
"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.levelByEnchantCost = EnchantScaler.read(this, 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.anvilMergeCost = EnchantScaler.read(this, "Anvil.Merge_Cost", Placeholders.ENCHANTMENT_LEVEL,
"Sets how much XP levels will be added to the anvil cost when combining custom enchantments.");
this.obtainChance = new HashMap<>();
this.obtainLevelCap = new HashMap<>();
for (ObtainType obtainType : ObtainType.values()) {
double obtainChance = cfg.getDouble(obtainType.getPathName() + ".Chance");
double obtainChance = JOption.create(obtainType.getPathName() + ".Chance", 50D,
"Chance for this enchantment to be obtained via " + obtainType.getPathName()).read(cfg);
this.obtainChance.put(obtainType, obtainChance);
int levelMin = cfg.getInt(obtainType.getPathName() + ".Level.Min", -1);
int levelMax = cfg.getInt(obtainType.getPathName() + ".Level.Max", -1);
this.obtainLevelCap.put(obtainType, Pair.of(levelMin, levelMax));
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.obtainLevelCap.put(obtainType, new int[]{levelMin, levelMax});
}
this.costEnabled = cfg.getBoolean("Settings.Cost.Enabled");
this.costItem = cfg.getItem("Settings.Cost.Item");
}
@Deprecated
protected void updateConfig() {
cfg.addMissing("Is_Treasure", false);
cfg.addMissing("Conflicts", new ArrayList<String>());
cfg.addMissing("Settings.Cost.Enabled", false);
cfg.addMissing("Settings.Cost.Item.Material", Material.AIR.name());
cfg.addMissing("Settings.Cost.Item.Amount", 1);
this.conflicts = JOption.create("Conflicts", new HashSet<>(),
"A list of conflicting enchantment names.",
"Conflicting enchantments can not be combined on anvils and obtained together on the same item.").read(cfg);
if (cfg.contains("Enchantment_Table")) {
String path = ObtainType.ENCHANTING.getPathName() + ".";
cfg.addMissing(path + "Chance", cfg.getDouble("Enchantment_Table.Chance"));
cfg.addMissing(path + "Level_By_Exp_Cost", cfg.getString("Enchantment_Table.Level_By_Exp_Cost", "30"));
cfg.remove("Enchantment_Table");
this.hasVisualEffects = JOption.create("Settings.Visual_Effects", true,
"Enables/Disables enchantment visual effects, such as particles.").read(cfg);
if (Config.ENCHANTMENTS_CHARGES_ENABLED.get()) {
this.chargesEnabled = JOption.create("Settings.Charges.Enabled", false,
"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.chargesCustomFuel = JOption.create("Settings.Charges.Custom_Fuel", false,
"When 'true' uses different (non-default) fuel item (from the 'Fuel_Item' setting) to recharge.").read(cfg);
this.chargesMax = EnchantScaler.read(this, "Settings.Charges.Maximum", "100",
"Maximum amount of charges for the enchantment.");
this.chargesConsumeAmount = EnchantScaler.read(this, "Settings.Charges.Consume_Amount", "1",
"How many charges will be consumed when enchantment is triggered?");
this.chargesRechargeAmount = EnchantScaler.read(this, "Settings.Charges.Recharge_Amount", "25",
"How many charges will be restored when using 'Fuel Item' in anvil?");
this.chargesFuel = 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);
}
for (ObtainType obtainType : ObtainType.values()) {
cfg.addMissing(obtainType.getPathName() + ".Chance", 25D);
cfg.addMissing(obtainType.getPathName() + ".Level.Min", -1);
cfg.addMissing(obtainType.getPathName() + ".Level.Max", -1);
/*cfg.setComments(obtainType.getPathName() + ".Level", Arrays.asList(
"Here you can set min. and max. level for enchantment generated via " + obtainType.getPathName().replace("_", " "),
"These levels can not be greater or smaller than the default enchantment min. and max levels.",
"Set min/max level to -1 to use the default enchantment min/max level value."
));*/
}
/*String scalabe = "Scalable. Placeholder: " + PLACEHOLDER_LEVEL + ". See: http://77.222.60.131:8080/plugin/engine/config/formats";
cfg.setComments("Is_Treasure", Arrays.asList("Defines if this enchantment is a treasure enchantment.", "Treasure enchantments can only be received via looting, trading, or fishing."));
cfg.setComments("Name", Arrays.asList("Enchantment display name. This name will be displayed in item lore and in enchantments list GUI."));
cfg.setComments("Tier", Arrays.asList("Enchantment tier. Must be a valid tier from the 'config.yml'. Enchantments with invalid tier won't be loaded."));
cfg.setComments("Description", Arrays.asList("Enchantment description. Will be displayed in item lore (if not disabled in the main config.yml) and in enchantments list GUI.", "You can use multiple lines here.", "You can use 'Enchantment' placeholders: http://77.222.60.131:8080/plugin/excellentenchants/utils/placeholders"));
cfg.setComments("Level", Arrays.asList("Enchantment level settings."));
cfg.setComments("Level.Min", Arrays.asList("Minimal (start) enchantment level. Can not be smaller then 1."));
cfg.setComments("Level.Max", Arrays.asList("Maximal (final) enchantment level.", "Keep in mind that while you can enchant items with bypass max. enchantment level, all enchantment 'Scalable' option values will not exceed the max. enchantment level."));
cfg.setComments("Anvil", Arrays.asList("Enchantment settings for Anvil."));
cfg.setComments("Anvil.Merge_Cost", Arrays.asList("Defines the exp cost to merge this enchantment on other items on anvil.", scalabe));
cfg.setComments("Enchanting_Table", Arrays.asList("Enchantment settings for Enchanting Table."));
cfg.setComments("Enchanting_Table.Level_By_Exp_Cost", Arrays.asList("Defines which enchantment level will be generated in Enchanting Table depends on the enchanting cost.", "Example: expression '9 * %enchantment_level%' for enchantment levels 1-3 will result in I = 9+ Levels, II = 18+ Levels, III = 27+ Levels.", scalabe));
cfg.setComments("Enchanting_Table.Chance", Arrays.asList("A chance that this enchantment will be appeared in Enchanting Table."));
cfg.setComments("Villagers.Chance", Arrays.asList("A chance that this enchantment will be populated on items in Villager trades."));
cfg.setComments("Loot_Generation.Chance", Arrays.asList("A chance that this enchantment will be populated on items in cave/dungeon/castle chests/minecarts and other containers."));
cfg.setComments("Fishing.Chance", Arrays.asList("A chance that this enchantment will be populated on items received from fishing."));
cfg.setComments("Mob_Spawning.Chance", Arrays.asList("A chance that this enchantment will be populated on items equipped on mob on spawning."));
cfg.setComments("Settings", Arrays.asList("Individual enchantment settings."));
cfg.setComments("Settings.Trigger_Chance", Arrays.asList("A chance that this enchantment will be triggered.", scalabe));
cfg.setComments("Settings.Cost", Arrays.asList("A cost a player will have to pay to have this enchantment triggered."));
cfg.setComments("Settings.Cost.Enabled", Arrays.asList("Enables/Disables cost feature."));
cfg.setComments("Settings.Cost.Item", Arrays.asList("A (custom) item that player must have in his inventory, that will be consumed to trigger the enchantment effect.", "See http://77.222.60.131:8080/plugin/engine/config/formats for item options."));
cfg.setComments("Settings.Potion_Effect", Arrays.asList("Enchantment settings for the Potion Effect applied to a wearer or victim."));
cfg.setComments("Settings.Potion_Effect.Level", Arrays.asList("Potion effect level (amplifier).", scalabe));
cfg.setComments("Settings.Potion_Effect.Duration", Arrays.asList("Potion effect duration (in seconds). Keep in mind that settings this to a low value (smaller than Passive Task Interval in the config.yml) will result in effect reappear delay.", scalabe));
cfg.setComments("Settings.Particle", Arrays.asList("Particle effect that will be played on enchantment trigger."));
cfg.setComments("Settings.Particle.Name", Arrays.asList("Particle name. Set this to empty '' or 'NONE' to disable.", "https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Particle.html"));
cfg.setComments("Settings.Particle.Data", Arrays.asList("Particle data (additional settings).", "- BLOCK_DUST, BLOCK_MARKER, BLOCK_CRACK, ITEM_CRACK, FALLING_DUST: Use https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html", "- REDSTONE: Use RGB (like 255,255,255)"));
cfg.setComments("Settings.Sound", Arrays.asList("Sound that will be played on enchantment trigger.", "https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html"));
cfg.setComments("Settings.Arrow", Arrays.asList("Enchantment arrow settings."));
cfg.setComments("Settings.Arrow.Trail", Arrays.asList("A particle effect to play as an arrow trail."));
cfg.setComments("Settings.Arrow.Trail.Name", Arrays.asList("Particle name. Set this to empty '' or 'NONE' to disable.", "https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Particle.html"));
cfg.setComments("Settings.Arrow.Trail.Data", Arrays.asList("Particle data (additional settings).", "- BLOCK_DUST, BLOCK_MARKER, BLOCK_CRACK, ITEM_CRACK, FALLING_DUST: Use https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html", "- REDSTONE: Use RGB (like 255,255,255)"));
List<String> placeholders = new ArrayList<>();
placeholders.add("Additional placeholders:");
for (Field field : Reflex.getFields(this.getClass())) {
if (field.getType() != String.class) continue;
if (!field.getName().startsWith("PLACEHOLDER")) continue;
if (field.getDeclaringClass().equals(ExcellentEnchant.class)) continue;
String value = (String) Reflex.getFieldValue(this, field.getName());
String name = StringUtil.capitalizeFully(value.replace("%", "").replace("_", " "));
placeholders.add("- " + value + ": " + name.trim());
}
cfg.options().setHeader(placeholders);*/
}
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
String conflicts = this.getConflicts().isEmpty() ? plugin.getMessage(Lang.OTHER_NONE).getLocalized() : this.getConflicts().stream().filter(Objects::nonNull).map(LangManager::getEnchantment).collect(Collectors.joining("\n"));
return str -> {
str = str.replace(Placeholders.ENCHANTMENT_DESCRIPTION, String.join("\n", this.getDescription()));
return str -> str
.replace(Placeholders.ENCHANTMENT_NAME, this.getDisplayName())
.replace(Placeholders.ENCHANTMENT_NAME_FORMATTED, this.getNameFormatted(level))
.replace(Placeholders.ENCHANTMENT_LEVEL, NumberUtil.toRoman(level))
.replace(Placeholders.ENCHANTMENT_LEVEL_MIN, String.valueOf(this.getStartLevel()))
.replace(Placeholders.ENCHANTMENT_LEVEL_MAX, String.valueOf(this.getMaxLevel()))
.replace(Placeholders.ENCHANTMENT_TARGET, plugin.getLangManager().getEnum(this.getItemTarget()))
.replace(Placeholders.ENCHANTMENT_TIER, this.getTier().getName())
.replace(Placeholders.ENCHANTMENT_CONFLICTS, conflicts)
.replace(Placeholders.ENCHANTMENT_FIT_ITEM_TYPES, String.join(", ", Stream.of(this.getFitItemTypes()).map(type -> plugin.getLangManager().getEnum(type)).toList()))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING, NumberUtil.format(this.getObtainChance(ObtainType.ENCHANTING)))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_VILLAGER, NumberUtil.format(this.getObtainChance(ObtainType.VILLAGER)))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_LOOT_GENERATION, NumberUtil.format(this.getObtainChance(ObtainType.LOOT_GENERATION)))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_FISHING, NumberUtil.format(this.getObtainChance(ObtainType.FISHING)))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_MOB_SPAWNING, NumberUtil.format(this.getObtainChance(ObtainType.MOB_SPAWNING)))
.replace(Placeholders.ENCHANTMENT_COST_ITEM, this.hasCostItem() ? ItemUtil.getItemName(this.costItem) : plugin.getMessage(Lang.OTHER_NONE).getLocalized())
if (this instanceof Chanced chanced) {
str = str.replace(ChanceImplementation.PLACEHOLDER_CHANCE, NumberUtil.format(chanced.getTriggerChance(level)));
}
if (this instanceof Potioned potioned) {
str = str
.replace(PotionImplementation.PLACEHOLDER_POTION_LEVEL, NumberUtil.toRoman(potioned.getEffectAmplifier(level)))
.replace(PotionImplementation.PLACEHOLDER_POTION_DURATION, NumberUtil.format((double) potioned.getEffectDuration(level) / 20D))
.replace(PotionImplementation.PLACEHOLDER_POTION_TYPE, LangManager.getPotionType(potioned.getEffectType()));
}
return str
.replace(Placeholders.ENCHANTMENT_NAME, this.getDisplayName())
.replace(Placeholders.ENCHANTMENT_NAME_FORMATTED, this.getNameFormatted(level))
.replace(Placeholders.ENCHANTMENT_LEVEL, NumberUtil.toRoman(level))
.replace(Placeholders.ENCHANTMENT_LEVEL_MIN, String.valueOf(this.getStartLevel()))
.replace(Placeholders.ENCHANTMENT_LEVEL_MAX, String.valueOf(this.getMaxLevel()))
.replace(Placeholders.ENCHANTMENT_TIER, this.getTier().getName())
.replace(Placeholders.ENCHANTMENT_FIT_ITEM_TYPES, String.join(", ", Stream.of(this.getFitItemTypes()).map(type -> plugin.getLangManager().getEnum(type)).toList()))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING, NumberUtil.format(this.getObtainChance(ObtainType.ENCHANTING)))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_VILLAGER, NumberUtil.format(this.getObtainChance(ObtainType.VILLAGER)))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_LOOT_GENERATION, NumberUtil.format(this.getObtainChance(ObtainType.LOOT_GENERATION)))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_FISHING, NumberUtil.format(this.getObtainChance(ObtainType.FISHING)))
.replace(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_MOB_SPAWNING, NumberUtil.format(this.getObtainChance(ObtainType.MOB_SPAWNING)))
.replace(Placeholders.ENCHANTMENT_CHARGES_MAX_AMOUNT, String.valueOf(this.getChargesMax(level)))
.replace(Placeholders.ENCHANTMENT_CHARGES_CONSUME_AMOUNT, String.valueOf(this.getChargesConsumeAmount(level)))
.replace(Placeholders.ENCHANTMENT_CHARGES_RECHARGE_AMOUNT, String.valueOf(this.getChargesRechargeAmount(level)))
.replace(Placeholders.ENCHANTMENT_CHARGES_FUEL_ITEM, ItemUtil.getItemName(this.getChargesFuel()))
;
};
}
@Override
public void registerListeners() {
this.addConflicts();
this.plugin.getPluginManager().registerEvents(this, plugin);
}
@NotNull
public UnaryOperator<String> formatString(int level) {
return str -> this.replacePlaceholders(level).apply(str
.replace(Placeholders.ENCHANTMENT_DESCRIPTION, String.join("\n", Config.formatDescription(this.getDescription())))
);
}
@NotNull
public FitItemType[] getFitItemTypes() {
FitItemType itemType = FitItemType.getByEnchantmentTarget(this.getItemTarget());
return itemType == null ? new FitItemType[0] : new FitItemType[]{itemType};
}
private void addConflicts() {
this.conflicts.addAll(this.getConfig().getStringSet("Conflicts").stream()
.map(enchId -> Enchantment.getByKey(NamespacedKey.minecraft(enchId.toLowerCase())))
.filter(Objects::nonNull)
.toList());
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);
}
public boolean hasCostItem() {
return this.costEnabled && !this.costItem.getType().isAir();
}
public boolean takeCostItem(@NotNull LivingEntity livingEntity) {
if (!this.hasCostItem()) return true;
if (!(livingEntity instanceof Player player)) return true;
if (PlayerUtil.countItem(player, this.costItem) < this.costItem.getAmount()) return false;
return PlayerUtil.takeItem(player, this.costItem, this.costItem.getAmount());
}
public boolean isEnchantmentAvailable(@NotNull LivingEntity entity) {
return !Config.isEnchantmentDisabled(this, entity.getWorld().getName());
public boolean isAvailableToUse(@NotNull LivingEntity entity) {
return !this.isDisabledInWorld(entity.getWorld());
}
@NotNull
@ -266,6 +240,19 @@ public abstract class ExcellentEnchant extends Enchantment implements IListener
return this.getTier().getColor() + this.getDisplayName() + " " + NumberUtil.toRoman(level);
}
@NotNull
public String getNameFormatted(int level, int charges) {
if (!this.isChargesEnabled()) return this.getNameFormatted(level);
int chargesMax = this.getChargesMax(level);
double percent = (double) charges / (double) chargesMax * 100D;
Map.Entry<Double, 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.description;
@ -279,12 +266,19 @@ public abstract class ExcellentEnchant extends Enchantment implements IListener
}
@NotNull
public Set<Enchantment> getConflicts() {
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());
}
@NotNull
public Set<String> getConflicts() {
return conflicts;
}
@NotNull
public EnchantTier getTier() {
public Tier getTier() {
return this.tier;
}
@ -311,11 +305,11 @@ public abstract class ExcellentEnchant extends Enchantment implements IListener
}
public int getObtainLevelMin(@NotNull ObtainType obtainType) {
return this.obtainLevelCap.getOrDefault(obtainType, Pair.of(-1, -1)).getFirst();
return this.obtainLevelCap.getOrDefault(obtainType, new int[]{-1, -1})[0];
}
public int getObtainLevelMax(@NotNull ObtainType obtainType) {
return this.obtainLevelCap.getOrDefault(obtainType, Pair.of(-1, -1)).getSecond();
return this.obtainLevelCap.getOrDefault(obtainType, new int[]{-1, -1})[1];
}
public int fineLevel(int level, @NotNull ObtainType obtainType) {
@ -348,14 +342,14 @@ public abstract class ExcellentEnchant extends Enchantment implements IListener
@Override
public final boolean conflictsWith(@NotNull Enchantment enchantment) {
return this.conflicts.contains(enchantment);
return this.conflicts.contains(enchantment.getKey().getKey());
}
@Override
public final boolean canEnchantItem(@Nullable ItemStack item) {
if (item == null || item.getType().isAir()) return false;
if (EnchantManager.getItemEnchants(item).keySet().stream().anyMatch(e -> e.conflictsWith(this) || this.conflictsWith(e))) return false;
if (EnchantManager.getEnchantmentLevel(item, this) <= 0 && EnchantManager.getItemCustomEnchantsAmount(item) >= Config.ENCHANTMENTS_ITEM_CUSTOM_MAX) {
if (EnchantManager.getEnchantments(item).keySet().stream().anyMatch(e -> e.conflictsWith(this) || this.conflictsWith(e))) return false;
if (EnchantManager.getEnchantmentLevel(item, this) <= 0 && EnchantManager.getExcellentEnchantmentsAmount(item) >= Config.ENCHANTMENTS_ITEM_CUSTOM_MAX.get()) {
return false;
}
if (item.getType() == Material.BOOK || item.getType() == Material.ENCHANTED_BOOK) {
@ -373,4 +367,61 @@ public abstract class ExcellentEnchant extends Enchantment implements IListener
public final boolean isTreasure() {
return this.isTreasure;
}
public boolean hasVisualEffects() {
return this.hasVisualEffects;
}
public boolean isChargesEnabled() {
return Config.ENCHANTMENTS_CHARGES_ENABLED.get() && this.chargesEnabled;
}
public boolean isChargesCustomFuel() {
return chargesCustomFuel;
}
public int getChargesMax(int level) {
return this.isChargesEnabled() ? (int) this.chargesMax.getValue(level) : 0;
}
public int getChargesConsumeAmount(int level) {
return this.isChargesEnabled() ? (int) this.chargesConsumeAmount.getValue(level) : 0;
}
public int getChargesRechargeAmount(int level) {
return this.isChargesEnabled() ? (int) this.chargesRechargeAmount.getValue(level) : 0;
}
@NotNull
public ItemStack getChargesFuel() {
ItemStack fuelHas = this.chargesFuel;
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) {
return item.isSimilar(this.getChargesFuel());
}
@NotNull
public NamespacedKey getChargesKey() {
return chargesKey;
}
@Override
public boolean isOutOfCharges(@NotNull ItemStack item) {
return EnchantManager.isEnchantmentOutOfCharges(item, this);
}
@Override
public boolean isFullOfCharges(@NotNull ItemStack item) {
return EnchantManager.isEnchantmentFullOfCharges(item, this);
}
@Override
public void consumeCharges(@NotNull ItemStack item) {
EnchantManager.consumeEnchantmentCharges(item, this);
}
}

View File

@ -1,72 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.enchantments.EnchantmentTarget;
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.metadata.FixedMetadataValue;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.manager.EnchantManager;
public abstract class IEnchantBowPotionTemplate extends IEnchantPotionTemplate implements BowEnchant {
protected final String arrowMeta;
public IEnchantBowPotionTemplate(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg,
@NotNull EnchantPriority priority,
@NotNull PotionEffectType type) {
super(plugin, cfg, priority, type);
this.arrowMeta = this.getId() + "_potion_arrow";
}
public boolean isThisArrow(@NotNull Projectile projectile) {
return projectile.hasMetadata(this.arrowMeta);
}
public void setThisArrow(@NotNull Projectile projectile) {
projectile.setMetadata(this.arrowMeta, new FixedMetadataValue(plugin, true));
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BOW;
}
@Override
public boolean use(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (!this.isThisArrow(projectile)) return false;
return true;
}
@Override
public boolean use(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isEnchantmentAvailable(shooter)) return false;
if (!(e.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!EnchantManager.hasEnchantment(bow, ARROW_INFINITE) && !this.takeCostItem(shooter)) return false;
this.setThisArrow(arrow);
arrow.addCustomEffect(this.getEffect(level), true);
return true;
}
@Override
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isEnchantmentAvailable(victim)) return false;
if (!(e.getDamager() instanceof Projectile projectile)) return false;
if (!this.isThisArrow(projectile)) return false;
//this.addEffect(victim, level);
return true;
}
}

View File

@ -1,92 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
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.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.tasks.ArrowTrailsTask;
public abstract class IEnchantBowTemplate extends IEnchantChanceTemplate implements BowEnchant {
protected String arrowTrailName;
protected String arrowTrailData;
protected final String arrowMeta;
public IEnchantBowTemplate(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg, @NotNull EnchantPriority priority) {
super(plugin, cfg, priority);
this.arrowMeta = this.getId() + "_arrow";
}
@Override
public void loadConfig() {
super.loadConfig();
this.arrowTrailName = cfg.getString("Settings.Arrow.Trail.Name", "");
this.arrowTrailData = cfg.getString("Settings.Arrow.Trail.Data", "");
}
@Override
protected void updateConfig() {
super.updateConfig();
if (cfg.contains("Settings.Arrow.Trail") && !cfg.isConfigurationSection("Settings.Arrow.Trail")) {
String trail = cfg.getString("Settings.Arrow.Trail", "");
cfg.set("Settings.Arrow.Trail", null);
cfg.addMissing("Settings.Arrow.Trail.Name", trail);
}
cfg.addMissing("Settings.Arrow.Trail.Data", "");
}
public boolean isThisArrow(@NotNull Projectile projectile) {
return projectile.hasMetadata(this.arrowMeta);
}
public void setThisArrow(@NotNull Projectile projectile) {
projectile.setMetadata(this.arrowMeta, new FixedMetadataValue(plugin, true));
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BOW;
}
@Override
public boolean use(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (!this.isThisArrow(projectile)) return false;
return true;
}
@Override
public boolean use(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isEnchantmentAvailable(shooter)) return false;
if (!(e.getProjectile() instanceof Projectile arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!EnchantManager.hasEnchantment(bow, ARROW_INFINITE) && !this.takeCostItem(shooter)) return false;
this.setThisArrow(arrow);
if (!this.arrowTrailName.isEmpty()) {
ArrowTrailsTask.add(arrow, this.arrowTrailName, this.arrowTrailData);
}
return true;
}
@Override
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isEnchantmentAvailable(victim)) return false;
if (!(e.getDamager() instanceof Projectile projectile)) return false;
if (!this.isThisArrow(projectile)) return false;
return true;
}
}

View File

@ -1,56 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import java.util.function.UnaryOperator;
public abstract class IEnchantChanceTemplate extends ExcellentEnchant {
public static final String PLACEHOLDER_CHANCE = "%enchantment_trigger_chance%";
protected Scaler triggerChance;
public IEnchantChanceTemplate(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg, @NotNull EnchantPriority priority) {
super(plugin, cfg, priority);
}
@Override
public void loadConfig() {
super.loadConfig();
this.triggerChance = new EnchantScaler(this, "Settings.Trigger_Chance");
}
@Override
protected void updateConfig() {
super.updateConfig();
if (cfg.contains("settings.enchant-trigger-chance")) {
String triggerChance = cfg.getString("settings.enchant-trigger-chance", "100").replace("%level%", Placeholders.ENCHANTMENT_LEVEL);
cfg.set("Settings.Trigger_Chance", triggerChance);
cfg.set("settings.enchant-trigger-chance", null);
}
}
@Override
public @NotNull UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
.replace(PLACEHOLDER_CHANCE, NumberUtil.format(this.getTriggerChance(level)))
);
}
public final double getTriggerChance(int level) {
return this.triggerChance.getValue(level);
}
public final boolean checkTriggerChance(int level) {
return Rnd.get(true) <= this.getTriggerChance(level);
}
}

View File

@ -1,57 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.api.config.JYML;
import su.nexmedia.engine.utils.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
public abstract class IEnchantCombatPotionTemplate extends IEnchantPotionTemplate implements CombatEnchant {
protected String particleName;
protected String particleData;
public IEnchantCombatPotionTemplate(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg,
@NotNull EnchantPriority priority,
@NotNull PotionEffectType effectType) {
super(plugin, cfg, priority, effectType);
}
@Override
public void loadConfig() {
super.loadConfig();
this.particleName = cfg.getString("Settings.Particle.Name", "");
this.particleData = cfg.getString("Settings.Particle.Data", "");
}
@Override
protected void updateConfig() {
super.updateConfig();
cfg.remove("Settings.Particle_Effect");
cfg.addMissing("Settings.Particle.Name", "");
cfg.addMissing("Settings.Particle.Data", "");
}
@Override
@NotNull
public final EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isEnchantmentAvailable(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(damager)) return false;
if (!this.addEffect(victim, level)) return false;
EffectUtil.playEffect(victim.getEyeLocation(), this.particleName, this.particleData, 0.25f, 0.25f, 0.25f, 0.1f, 50);
return true;
}
}

View File

@ -1,90 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.lang.LangManager;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import java.util.function.UnaryOperator;
public abstract class IEnchantPotionTemplate extends IEnchantChanceTemplate {
public static final String PLACEHOLDER_POTION_LEVEL = "%enchantment_potion_level%";
public static final String PLACEHOLDER_POTION_DURATION = "%enchantment_potion_duration%";
public static final String PLACEHOLDER_POTION_TYPE = "%enchantment_potion_type%";
protected PotionEffectType potionEffectType;
protected final boolean potionParticles;
protected Scaler potionDuration;
protected Scaler potionLevel;
public IEnchantPotionTemplate(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg,
@NotNull EnchantPriority priority,
@NotNull PotionEffectType potionEffectType) {
super(plugin, cfg, priority);
this.potionEffectType = potionEffectType;
this.potionParticles = !(this instanceof PassiveEnchant);
}
@Override
public void loadConfig() {
super.loadConfig();
this.potionDuration = new EnchantScaler(this, "Settings.Potion_Effect.Duration");
this.potionLevel = new EnchantScaler(this, "Settings.Potion_Effect.Level");
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
.replace(PLACEHOLDER_POTION_LEVEL, NumberUtil.toRoman(this.getEffectLevel(level)))
.replace(PLACEHOLDER_POTION_DURATION, NumberUtil.format((double) this.getEffectDuration(level) / 20D))
.replace(PLACEHOLDER_POTION_TYPE, LangManager.getPotionType(this.getEffectType()))
);
}
@NotNull
public final PotionEffectType getEffectType() {
return this.potionEffectType;
}
public final int getEffectDuration(int level) {
return (int) (this.potionDuration.getValue(level) * 20);
}
public final int getEffectLevel(int level) {
return (int) this.potionLevel.getValue(level);
}
@NotNull
public PotionEffect getEffect(int level) {
int duration = this.getEffectDuration(level);
int amplifier = Math.max(0, this.getEffectLevel(level) - 1);
return new PotionEffect(this.potionEffectType, duration, amplifier, false, this.potionParticles);
}
public final boolean hasEffect(@NotNull LivingEntity entity) {
return EnchantManager.hasEnchantmentEffect(entity, this);
}
public final boolean addEffect(@NotNull LivingEntity target, int level) {
if (this instanceof PassiveEnchant) {
if (!this.hasEffect(target)) {
this.plugin.getEnchantNMS().addEnchantmentEffect(target, this, this.getEffect(level));
}
}
else {
target.addPotionEffect(this.getEffect(level));
}
return true;
}
}

View File

@ -0,0 +1,78 @@
package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.enchantments.Enchantment;
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.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.tier.Tier;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import java.util.List;
import java.util.Set;
public interface IEnchantment {
@NotNull JYML getConfig();
@NotNull String getId();
@NotNull EnchantPriority getPriority();
@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);
boolean isFullOfCharges(@NotNull ItemStack item);
boolean isOutOfCharges(@NotNull ItemStack item);
void consumeCharges(@NotNull ItemStack item);
}

View File

@ -0,0 +1,34 @@
package su.nightexpress.excellentenchants.api.enchantment.meta;
import org.bukkit.Particle;
import org.bukkit.entity.Projectile;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public interface Arrowed {
@NotNull Arrowed getArrowImplementation();
@NotNull
default Optional<Particle> getTrailParticle() {
return this.getArrowImplementation().getTrailParticle();
}
@NotNull
default Optional<String> getTrailData() {
return this.getArrowImplementation().getTrailData();
}
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

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

View File

@ -0,0 +1,44 @@
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();
/*@NotNull
default UnaryOperator<String> replacePlaceholders(int level) {
return this.getPotionImplementation().replacePlaceholders(level);
}*/
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 hasEffect(@NotNull LivingEntity target) {
return this.getPotionImplementation().hasEffect(target);
}
default boolean addEffect(@NotNull LivingEntity target, int level) {
return this.getPotionImplementation().addEffect(target, level);
}
}

View File

@ -0,0 +1,36 @@
package su.nightexpress.excellentenchants.api.enchantment.template;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
public abstract class PotionEnchant extends ExcellentEnchant implements Potioned {
private final PotionEffectType effectType;
private final boolean isPermanent;
private PotionImplementation potionImplementation;
public PotionEnchant(@NotNull ExcellentEnchants plugin, @NotNull String id, @NotNull EnchantPriority priority,
@NotNull PotionEffectType effectType, boolean isPermanent) {
super(plugin, id, priority);
this.effectType = effectType;
this.isPermanent = isPermanent;
}
@Override
public void loadConfig() {
super.loadConfig();
this.potionImplementation = PotionImplementation.create(this, this.effectType, this.isPermanent);
}
@Override
@NotNull
public Potioned getPotionImplementation() {
return this.potionImplementation;
}
}

View File

@ -4,8 +4,9 @@ import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
public interface BlockBreakEnchant {
public interface BlockBreakEnchant extends IEnchantment {
boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level);
boolean onBreak(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level);
}

View File

@ -4,8 +4,11 @@ import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantDropContainer;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
public interface BlockDropEnchant {
public interface BlockDropEnchant extends IEnchantment {
boolean use(@NotNull BlockDropItemEvent e, @NotNull Player player, @NotNull ItemStack item, int level);
boolean onDrop(@NotNull BlockDropItemEvent e, @NotNull EnchantDropContainer dropContainer,
@NotNull Player player, @NotNull ItemStack item, int level);
}

View File

@ -2,14 +2,20 @@ package su.nightexpress.excellentenchants.api.enchantment.type;
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.api.enchantment.IEnchantment;
public interface BowEnchant extends CombatEnchant {
public interface BowEnchant extends IEnchantment {
boolean use(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level);
boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level);
boolean use(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level);
boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level);
boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile,
@NotNull LivingEntity shooter, @NotNull LivingEntity victim,
@NotNull ItemStack weapon, int level);
}

View File

@ -4,8 +4,15 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
public interface CombatEnchant {
public interface CombatEnchant extends IEnchantment {
boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level);
boolean onAttack(@NotNull EntityDamageByEntityEvent e,
@NotNull LivingEntity damager, @NotNull LivingEntity victim,
@NotNull ItemStack weapon, int level);
boolean onProtect(@NotNull EntityDamageByEntityEvent e,
@NotNull LivingEntity damager, @NotNull LivingEntity victim,
@NotNull ItemStack weapon, int level);
}

View File

@ -1,11 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment.type;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.EnchantDropContainer;
public interface CustomDropEnchant {
void handleDrop(@NotNull EnchantDropContainer e, @NotNull Player player, @NotNull ItemStack item, int level);
}

View File

@ -0,0 +1,12 @@
package su.nightexpress.excellentenchants.api.enchantment.type;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
public interface DamageEnchant extends IEnchantment {
boolean onDamage(@NotNull EntityDamageEvent e, @NotNull LivingEntity entity, @NotNull ItemStack item, int level);
}

View File

@ -1,10 +1,14 @@
package su.nightexpress.excellentenchants.api.enchantment.type;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDeathEvent;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
public interface DeathEnchant {
public interface DeathEnchant extends IEnchantment {
boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level);
boolean onDeath(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, int level);
boolean onKill(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, @NotNull Player killer, int level);
}

View File

@ -4,8 +4,9 @@ import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
public interface InteractEnchant {
public interface InteractEnchant extends IEnchantment {
boolean use(@NotNull PlayerInteractEvent e, @NotNull Player player, @NotNull ItemStack item, int level);
boolean onInteract(@NotNull PlayerInteractEvent e, @NotNull Player player, @NotNull ItemStack item, int level);
}

View File

@ -1,10 +0,0 @@
package su.nightexpress.excellentenchants.api.enchantment.type;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.player.PlayerMoveEvent;
import org.jetbrains.annotations.NotNull;
public interface MoveEnchant {
boolean use(@NotNull PlayerMoveEvent e, @NotNull LivingEntity entity, int level);
}

View File

@ -1,9 +1,11 @@
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;
public interface PassiveEnchant {
public interface PassiveEnchant extends IEnchantment {
boolean use(@NotNull LivingEntity entity, int level);
boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level);
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.api.enchantment;
package su.nightexpress.excellentenchants.api.enchantment.util;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack;

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.api.enchantment;
package su.nightexpress.excellentenchants.api.enchantment.util;
public enum EnchantPriority {

View File

@ -6,7 +6,6 @@ import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.command.AbstractCommand;
import su.nexmedia.engine.lang.LangManager;
@ -15,7 +14,9 @@ import su.nexmedia.engine.utils.StringUtil;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Perms;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import java.util.Arrays;
import java.util.List;
@ -84,17 +85,12 @@ public class BookCommand extends AbstractCommand<ExcellentEnchants> {
}
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta();
if (meta == null) return;
meta.addStoredEnchant(enchantment, level, true);
item.setItemMeta(meta);
//EnchantManager.updateItemLoreEnchants(item);
EnchantManager.addEnchantment(item, enchantment, level, true);
PlayerUtil.addItem(player, item);
plugin.getMessage(Lang.COMMAND_BOOK_DONE)
.replace("%enchant%", LangManager.getEnchantment(enchantment))
.replace("%player%", player.getName()).send(sender);
.replace(Placeholders.GENERIC_ENCHANT, LangManager.getEnchantment(enchantment))
.replace(Placeholders.Player.replacer(player))
.send(sender);
}
}

View File

@ -5,8 +5,6 @@ import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.command.AbstractCommand;
import su.nexmedia.engine.utils.StringUtil;
@ -14,6 +12,7 @@ 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.EnchantManager;
import java.util.Arrays;
import java.util.List;
@ -79,27 +78,10 @@ public class EnchantCommand extends AbstractCommand<ExcellentEnchants> {
level = Rnd.get(enchantment.getStartLevel(), enchantment.getMaxLevel());
}
ItemMeta meta = item.getItemMeta();
if (meta == null) return;
if (meta instanceof EnchantmentStorageMeta storageMeta) {
if (level == 0) {
storageMeta.removeStoredEnchant(enchantment);
}
else {
storageMeta.addStoredEnchant(enchantment, level, true);
}
if (level > 0) {
EnchantManager.addEnchantment(item, enchantment, level, true);
}
else {
if (level == 0) {
meta.removeEnchant(enchantment);
}
else {
meta.addEnchant(enchantment, level, true);
}
}
item.setItemMeta(meta);
//EnchantManager.updateItemLoreEnchants(item);
else EnchantManager.removeEnchantment(item, enchantment);
plugin.getMessage(Lang.COMMAND_ENCHANT_DONE).send(sender);
}

View File

@ -6,6 +6,7 @@ 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.utils.Placeholders;
import su.nexmedia.engine.utils.PlayerUtil;
import su.nexmedia.engine.utils.StringUtil;
import su.nexmedia.engine.utils.random.Rnd;
@ -13,8 +14,8 @@ import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Perms;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.config.Lang;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantTier;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.tier.Tier;
import java.util.Arrays;
import java.util.List;
@ -50,7 +51,7 @@ public class TierbookCommand extends AbstractCommand<ExcellentEnchants> {
return PlayerUtil.getPlayerNames();
}
if (arg == 2) {
return EnchantManager.getTierIds();
return plugin.getTierManager().getTierIds();
}
if (arg == 3) {
return Arrays.asList("-1", "1", "5", "10");
@ -71,7 +72,7 @@ public class TierbookCommand extends AbstractCommand<ExcellentEnchants> {
return;
}
EnchantTier tier = EnchantManager.getTierById(args[2].toLowerCase());
Tier tier = plugin.getTierManager().getTierById(args[2].toLowerCase());
if (tier == null) {
plugin.getMessage(Lang.COMMAND_TIER_BOOK_ERROR).send(sender);
return;
@ -89,11 +90,12 @@ public class TierbookCommand extends AbstractCommand<ExcellentEnchants> {
}
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
EnchantManager.addEnchant(item, enchant, level, true);
EnchantManager.addEnchantment(item, enchant, level, true);
PlayerUtil.addItem(player, item);
plugin.getMessage(Lang.COMMAND_TIER_BOOK_DONE)
.replace("%tier%", tier.getName())
.replace("%player%", player.getName()).send(sender);
.replace(tier.replacePlaceholders())
.replace(Placeholders.Player.replacer(player))
.send(sender);
}
}

View File

@ -1,171 +1,103 @@
package su.nightexpress.excellentenchants.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.Placeholders;
import su.nexmedia.engine.utils.StringUtil;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.manager.object.EnchantTier;
import su.nightexpress.excellentenchants.manager.type.ObtainType;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import java.util.*;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Config {
public static long TASKS_ARROW_TRAIL_TICKS_INTERVAL;
public static final JOption<Integer> TASKS_PASSIVE_POTION_EFFECTS_APPLY_INTERVAL = JOption.create("General.Tasks.Passive_Potion_Effects.Apply_Interval", 150,
public static final JOption<Long> TASKS_ARROW_TRAIL_TICKS_INTERVAL = JOption.create("Tasks.Arrow_Trail.Tick_Interval", 1L,
"Sets how often (in ticks) arrow trail particle effects will be spawned behind the arrow.");
public static final JOption<Long> TASKS_PASSIVE_POTION_EFFECTS_APPLY_INTERVAL = JOption.create("Tasks.Passive_Potion_Effects.Apply_Interval", 150L,
"Sets how often (in ticks) the plugin will apply permanent potion effects from enchanted items to an entity who wear them.",
"This setting does NOT refreshes currently active effects, but only attempts to add them if absent."
);
public static Set<String> ENCHANTMENTS_DISABLED;
public static Map<String, Set<String>> ENCHANTMENTS_DISABLED_IN_WORLDS;
public static boolean ENCHANTMENTS_DESCRIPTION_ENABLED;
private static String ENCHANTMENTS_DESCRIPTION_FORMAT;
public static final JOption<Boolean> ENCHANTMENTS_CHARGES_ENABLED = JOption.create("Enchantments.Charges.Enabled", false,
"Enables the enchantment Charges feature."); // TODO Wiki link
public static int ENCHANTMENTS_ITEM_CUSTOM_MAX;
public static boolean ENCHANTMENTS_ITEM_AXES_AS_SWORDS;
public static boolean ENCHANTMENTS_ITEM_CROSSBOWS_AS_BOWS;
public static boolean ENCHANTMENTS_ITEM_ELYTRA_AS_CHESTPLATE;
public static boolean ENCHANTMENTS_ENTITY_PASSIVE_FOR_MOBS;
public static final JOption<TreeMap<Double, String>> ENCHANTMENTS_CHARGES_FORMAT = new JOption<TreeMap<Double, String>>("Enchantments.Charges.Format",
(cfg, path, def) -> cfg.getSection(path).stream().collect(Collectors.toMap(k -> StringUtil.getDouble(k, 0), v -> StringUtil.color(cfg.getString(path + "." + v, "")), (o,n) -> n, TreeMap::new)),
() -> {
TreeMap<Double, String> map = new TreeMap<>();
map.put(0D, "#ff9a9a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
map.put(25D, "#ffc39a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
map.put(50D, "#f6ff9a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
map.put(75D, "#bcff9a(" + Placeholders.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)));
private static Map<ObtainType, ObtainSettings> OBTAIN_SETTINGS;
private static Map<String, EnchantTier> TIERS;
public static final JOption<ItemStack> ENCHANTMENTS_CHARGES_FUEL_ITEM = JOption.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 void load(@NotNull ExcellentEnchants plugin) {
JYML cfg = plugin.getConfig();
cfg.initializeOptions(Config.class);
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.");
String path = "General.Tasks.";
TASKS_ARROW_TRAIL_TICKS_INTERVAL = cfg.getLong(path + "Arrow_Trails.Ticks_Interval", 1);
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)));
path = "General.Enchantments.";
cfg.addMissing(path + "Disabled_In_Worlds.my_world", Collections.singletonList(Placeholders.WILDCARD));
cfg.addMissing(path + "Disabled_In_Worlds.other_world", Arrays.asList("enchant_name", "another_enchant"));
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.",
"Note #1: You must have ProtocolLib installed for this feature to work (as well as for enchantments name display).",
"Note #2: Description is not shown while you're in Creative gamemode.");
ENCHANTMENTS_DISABLED = cfg.getStringSet(path + "Disabled").stream().map(String::toLowerCase).collect(Collectors.toSet());
ENCHANTMENTS_DISABLED_IN_WORLDS = new HashMap<>();
for (String worldName : cfg.getSection(path + "Disabled_In_Worlds")) {
ENCHANTMENTS_DISABLED_IN_WORLDS.put(worldName, cfg.getStringSet(path + "Disabled_In_Worlds." + worldName)
.stream().map(String::toLowerCase).collect(Collectors.toSet()));
}
public static final JOption<String> ENCHANTMENTS_DESCRIPTION_FORMAT = JOption.create("Enchantments.Description.Format",
"&8▸ " + Placeholders.GENERIC_DESCRIPTION,
"Sets the global enchantment description format.");
ENCHANTMENTS_DESCRIPTION_ENABLED = cfg.getBoolean(path + "Description.Enabled");
ENCHANTMENTS_DESCRIPTION_FORMAT = StringUtil.color(cfg.getString(path + "Description.Format", ""));
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?");
path = "General.Enchantments.Item.";
ENCHANTMENTS_ITEM_CUSTOM_MAX = cfg.getInt(path + "Max_Custom_Enchants", 3);
ENCHANTMENTS_ITEM_AXES_AS_SWORDS = cfg.getBoolean(path + "Axes_As_Swords");
ENCHANTMENTS_ITEM_CROSSBOWS_AS_BOWS = cfg.getBoolean(path + "Crossbows_As_Bows");
ENCHANTMENTS_ITEM_ELYTRA_AS_CHESTPLATE = cfg.getBoolean(path + "Elytra_As_Chestplate");
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.");
path = "General.Enchantments.Entity.";
ENCHANTMENTS_ENTITY_PASSIVE_FOR_MOBS = cfg.getBoolean(path + "Passive_Enchants_Applied_To_Mobs");
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.");
OBTAIN_SETTINGS = new HashMap<>();
for (ObtainType obtainType : ObtainType.values()) {
String path2 = "General." + obtainType.getPathName() + ".";
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.");
cfg.addMissing(path2 + "Enabled", true);
cfg.addMissing(path2 + "Enchantments.Total_Maximum", 4);
cfg.addMissing(path2 + "Enchantments.Custom_Generation_Chance", 50D);
cfg.addMissing(path2 + "Enchantments.Custom_Minimum", 0);
cfg.addMissing(path2 + "Enchantments.Custom_Maximum", 2);
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.");
if (!cfg.getBoolean(path2 + "Enabled")) continue;
int enchantsTotalMax = cfg.getInt(path2 + "Enchantments.Total_Maximum", 4);
double enchantsCustomGenerationChance = cfg.getDouble(path2 + "Enchantments.Custom_Generation_Chance", 50D);
int enchantsCustomMin = cfg.getInt(path2 + "Enchantments.Custom_Minimum", 0);
int enchantsCustomMax = cfg.getInt(path2 + "Enchantments.Custom_Maximum", 2);
ObtainSettings settings = new ObtainSettings(enchantsTotalMax, enchantsCustomGenerationChance, enchantsCustomMin, enchantsCustomMax);
OBTAIN_SETTINGS.put(obtainType, settings);
}
setupTiers(plugin);
}
private static void setupTiers(@NotNull ExcellentEnchants plugin) {
// Reloading tiers will reset their lists with enchants = break the plugin mechanics
if (ExcellentEnchants.isLoaded) return;
JYML cfg = plugin.getConfig();
TIERS = new HashMap<>();
// No tiers defined, setup a default one.
// Every enchantment must have a tier.
if (cfg.getSection("Tiers").isEmpty()) {
plugin.info("No tiers defined! Creating a default one for you...");
cfg.set("Tiers.default.Name", "&7Default");
cfg.set("Tiers.default.Color", "&7");
for (ObtainType obtainType : ObtainType.values()) {
cfg.set("Tiers.default.Obtain_Chance." + obtainType.name(), 100D);
}
}
// Load existing tiers.
for (String sId : cfg.getSection("Tiers")) {
String path = "Tiers." + sId + ".";
cfg.addMissing(path + "Priority", 0);
int priority = cfg.getInt(path + "Priority");
String name = cfg.getString(path + "Name", sId);
String color = cfg.getString(path + "Color", "&f");
Map<ObtainType, Double> chance = new HashMap<>();
for (ObtainType obtainType : ObtainType.values()) {
cfg.addMissing(path + "Obtain_Chance." + obtainType.name(), 50D);
double chanceType = cfg.getDouble(path + "Obtain_Chance." + obtainType.name());
chance.put(obtainType, chanceType);
}
EnchantTier tier = new EnchantTier(sId, priority, name, color, chance);
TIERS.put(tier.getId(), tier);
}
plugin.info("Tiers Loaded: " + TIERS.size());
}
public static boolean isEnchantmentDisabled(@NotNull ExcellentEnchant enchant, @NotNull String world) {
Set<String> disabled = ENCHANTMENTS_DISABLED_IN_WORLDS.getOrDefault(world, Collections.emptySet());
return disabled.contains(enchant.getKey().getKey()) || disabled.contains(Placeholders.WILDCARD);
}
@Nullable
public static EnchantTier getTierById(@NotNull String id) {
return TIERS.get(id.toLowerCase());
}
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)));
@NotNull
public static Collection<EnchantTier> getTiers() {
return TIERS.values();
}
@NotNull
public static List<String> getTierIds() {
return new ArrayList<>(TIERS.keySet());
}
@Nullable
public static EnchantTier getTierByChance(@NotNull ObtainType obtainType) {
Map<EnchantTier, Double> map = getTiers().stream().collect(Collectors.toMap(k -> k, v -> v.getChance(obtainType)));
return Rnd.get(map);
}
@Nullable
public static ObtainSettings getObtainSettings(@NotNull ObtainType obtainType) {
return OBTAIN_SETTINGS.get(obtainType);
}
@NotNull
public static List<String> formatDescription(@NotNull List<String> description) {
return new ArrayList<>(description.stream().map(line -> ENCHANTMENTS_DESCRIPTION_FORMAT.replace("%description%", line)).toList());
public static Optional<ObtainSettings> getObtainSettings(@NotNull ObtainType obtainType) {
ObtainSettings settings = OBTAIN_SETTINGS.get().get(obtainType);
return settings == null || !settings.isEnabled() ? Optional.empty() : Optional.of(settings);
}
}

View File

@ -2,6 +2,7 @@ package su.nightexpress.excellentenchants.config;
import su.nexmedia.engine.api.lang.LangKey;
import su.nexmedia.engine.lang.EngineLang;
import su.nightexpress.excellentenchants.Placeholders;
public class Lang extends EngineLang {
@ -13,13 +14,13 @@ public class Lang extends EngineLang {
public static final LangKey COMMAND_BOOK_USAGE = new LangKey("Command.Book.Usage", "<player> <enchant> <level>");
public static final LangKey COMMAND_BOOK_DESC = new LangKey("Command.Book.Desc", "Gives custom enchanted book.");
public static final LangKey COMMAND_BOOK_DONE = new LangKey("Command.Book.Done", "Given &6%enchant%&7 enchanted book to &6%player%&7.");
public static final LangKey COMMAND_BOOK_DONE = new LangKey("Command.Book.Done", "Given &6" + Placeholders.GENERIC_ENCHANT + "&7 enchanted book to &6" + Placeholders.Player.DISPLAY_NAME + "&7.");
public static final LangKey COMMAND_TIER_BOOK_USAGE = new LangKey("Command.TierBook.Usage", "<player> <tier> <level>");
public static final LangKey COMMAND_TIER_BOOK_DESC = new LangKey("Command.TierBook.Desc", "Gives an enchanted book.");
public static final LangKey COMMAND_TIER_BOOK_ERROR = new LangKey("Command.TierBook.Error", "&cInvalid tier!");
public static final LangKey COMMAND_TIER_BOOK_DONE = new LangKey("Command.TierBook.Done", "Given &6%tier%&7 enchanted book to &6%player%&7.");
public static final LangKey COMMAND_TIER_BOOK_DONE = new LangKey("Command.TierBook.Done", "Given &6" + Placeholders.TIER_NAME + "&7 enchanted book to &6" + Placeholders.Player.DISPLAY_NAME + "&7.");
public static final LangKey ERROR_NO_ENCHANT = new LangKey("Error.NoEnchant", "&cNo such enchant.");
public static final LangKey ERROR_NO_ENCHANT = new LangKey("Error.NoEnchant", "&cInvalid enchantment.");
}

View File

@ -1,19 +1,49 @@
package su.nightexpress.excellentenchants.config;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
public class ObtainSettings {
private final int enchantsTotalMax;
private final boolean isEnabled;
private final int enchantsTotalMax;
private final double enchantsCustomGenerationChance;
private final int enchantsCustomMin;
private final int enchantsCustomMax;
public ObtainSettings(int enchantsTotalMax, double enchantsCustomGenerationChance, int enchantsCustomMin, 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;
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager;
package su.nightexpress.excellentenchants.enchantment;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
@ -14,35 +14,37 @@ import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.api.manager.AbstractManager;
import su.nexmedia.engine.utils.EntityUtil;
import su.nexmedia.engine.utils.ItemUtil;
import su.nexmedia.engine.utils.PDCUtil;
import su.nexmedia.engine.utils.Pair;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.ExcellentEnchantsAPI;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.config.ObtainSettings;
import su.nightexpress.excellentenchants.manager.listeners.EnchantGenericListener;
import su.nightexpress.excellentenchants.manager.listeners.EnchantHandlerListener;
import su.nightexpress.excellentenchants.manager.object.EnchantListGUI;
import su.nightexpress.excellentenchants.manager.object.EnchantPopulator;
import su.nightexpress.excellentenchants.manager.object.EnchantTier;
import su.nightexpress.excellentenchants.manager.tasks.ArrowTrailsTask;
import su.nightexpress.excellentenchants.manager.tasks.EnchantEffectPassiveTask;
import su.nightexpress.excellentenchants.manager.type.ObtainType;
import su.nightexpress.excellentenchants.enchantment.listener.EnchantAnvilListener;
import su.nightexpress.excellentenchants.enchantment.listener.EnchantGenericListener;
import su.nightexpress.excellentenchants.enchantment.listener.EnchantHandlerListener;
import su.nightexpress.excellentenchants.enchantment.menu.EnchantmentsListMenu;
import su.nightexpress.excellentenchants.enchantment.task.ArrowTrailsTask;
import su.nightexpress.excellentenchants.enchantment.task.PotionEffectsTask;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import su.nightexpress.excellentenchants.tier.Tier;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class EnchantManager extends AbstractManager<ExcellentEnchants> {
private EnchantListGUI enchantListGUI;
private ArrowTrailsTask arrowTrailsTask;
private EnchantEffectPassiveTask enchantEffectPassiveTask;
private EnchantmentsListMenu enchantmentsListMenu;
private ArrowTrailsTask arrowTrailsTask;
private PotionEffectsTask potionEffectsTask;
public EnchantManager(@NotNull ExcellentEnchants plugin) {
super(plugin);
@ -52,44 +54,44 @@ public class EnchantManager extends AbstractManager<ExcellentEnchants> {
protected void onLoad() {
EnchantRegister.setup();
this.enchantListGUI = new EnchantListGUI(this.plugin);
this.enchantmentsListMenu = new EnchantmentsListMenu(this.plugin);
this.addListener(new EnchantHandlerListener(this));
this.addListener(new EnchantGenericListener(this));
this.addListener(new EnchantAnvilListener(this.plugin));
this.arrowTrailsTask = new ArrowTrailsTask(this.plugin);
this.arrowTrailsTask.start();
this.enchantEffectPassiveTask = new EnchantEffectPassiveTask(this.plugin);
this.enchantEffectPassiveTask.start();
this.potionEffectsTask = new PotionEffectsTask(this.plugin);
this.potionEffectsTask.start();
}
@Override
protected void onShutdown() {
if (this.enchantListGUI != null) {
this.enchantListGUI.clear();
this.enchantListGUI = null;
if (this.enchantmentsListMenu != null) {
this.enchantmentsListMenu.clear();
this.enchantmentsListMenu = null;
}
if (this.arrowTrailsTask != null) {
this.arrowTrailsTask.stop();
this.arrowTrailsTask = null;
}
if (this.enchantEffectPassiveTask != null) {
this.enchantEffectPassiveTask.stop();
this.enchantEffectPassiveTask = null;
if (this.potionEffectsTask != null) {
this.potionEffectsTask.stop();
this.potionEffectsTask = null;
}
EnchantRegister.shutdown();
}
@NotNull
public EnchantListGUI getEnchantsListGUI() {
return enchantListGUI;
public EnchantmentsListMenu getEnchantsListGUI() {
return enchantmentsListMenu;
}
public static boolean isEnchantable(@NotNull ItemStack item) {
if (item.getType().isAir()) return false;
return item.getType() == Material.ENCHANTED_BOOK || Stream.of(EnchantmentTarget.values()).anyMatch(target -> target.includes(item))
/*|| ItemUtil.isWeapon(item) || ItemUtil.isArmor(item) || ItemUtil.isTool(item) || ItemUtil.isBow(item)*/;
return item.getType() == Material.ENCHANTED_BOOK || Stream.of(EnchantmentTarget.values()).anyMatch(target -> target.includes(item));
}
@NotNull
@ -103,7 +105,7 @@ public class EnchantManager extends AbstractManager<ExcellentEnchants> {
@NotNull Function<ExcellentEnchant, Integer> levelFunc) {
Map<Enchantment, Integer> enchantsToAdd = new HashMap<>(enchantsPrepared);
ObtainSettings settings = Config.getObtainSettings(obtainType);
ObtainSettings settings = Config.getObtainSettings(obtainType).orElse(null);
if (settings == null || !Rnd.chance(settings.getEnchantsCustomGenerationChance())) return enchantsToAdd;
int enchMax = settings.getEnchantsTotalMax();
@ -118,7 +120,7 @@ public class EnchantManager extends AbstractManager<ExcellentEnchants> {
// Достигнут максимум чар (любых) для итема, заканчиваем.
if (enchantsToAdd.size() >= enchMax) break;
EnchantTier tier = populator.getTierByChance();
Tier tier = populator.getTierByChance();
if (tier == null) break; // Нет тира?
ExcellentEnchant enchant = populator.getEnchantByChance(tier);
@ -152,53 +154,19 @@ public class EnchantManager extends AbstractManager<ExcellentEnchants> {
}
public static boolean populateEnchantments(@NotNull ItemStack item, @NotNull ObtainType obtainType) {
int enchantsHad = EnchantManager.getItemCustomEnchantsAmount(item);
int enchantsHad = EnchantManager.getEnchantmentsAmount(item);
EnchantManager.getEnchantsToPopulate(item, obtainType).forEach((enchantment, level) -> {
EnchantManager.addEnchant(item, enchantment, level, false);
EnchantManager.addEnchantment(item, enchantment, level, false);
});
return EnchantManager.getItemCustomEnchantsAmount(item) != enchantsHad;
return EnchantManager.getEnchantmentsAmount(item) != enchantsHad;
}
@Deprecated
public static void updateItemLoreEnchants(@NotNull ItemStack item) {
EnchantRegister.ENCHANT_REGISTRY.values().forEach(ench -> {
//ItemUtil.delLore(item, ench.getId());
//ItemUtil.delLore(item, ench.getId() + "_info");
});
// Filter custom enchants and define map order.
Map<ExcellentEnchant, Integer> excellents = getItemCustomEnchants(item).entrySet().stream()
.sorted((e1,e2) -> e2.getKey().getTier().getPriority() - e1.getKey().getTier().getPriority())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (has, add) -> add, LinkedHashMap::new));
excellents.forEach((excellent, level) -> {
//ItemUtil.addLore(item, excellent.getId(), excellent.getNameFormatted(level), 0);
});
// Add enchantment description at the end of item lore.
if (Config.ENCHANTMENTS_DESCRIPTION_ENABLED) {
List<ExcellentEnchant> list = new ArrayList<>(excellents.keySet());
Collections.reverse(list);
list.forEach(excellent -> {
List<String> desc = excellent.getDescription(excellents.get(excellent));
if (desc.isEmpty()) return;
//ItemUtil.addLore(item, excellent.getId() + "_info", Config.formatDescription(desc), -1);
});
}
}
public static boolean addEnchant(@NotNull ItemStack item, @NotNull Enchantment enchantment, int level, boolean force) {
public static boolean addEnchantment(@NotNull ItemStack item, @NotNull Enchantment enchantment, int level, boolean force) {
if (!force && !enchantment.canEnchantItem(item)) return false;
EnchantManager.removeEnchant(item, enchantment);
//if (enchantment instanceof ExcellentEnchant excellentEnchant) {
//ItemUtil.addLore(item, excellentEnchant.getId(), excellentEnchant.getNameFormatted(level), 0);
//}
EnchantManager.removeEnchantment(item, enchantment);
ItemMeta meta = item.getItemMeta();
if (meta == null) return false;
@ -214,11 +182,7 @@ public class EnchantManager extends AbstractManager<ExcellentEnchants> {
return true;
}
public static void removeEnchant(@NotNull ItemStack item, @NotNull Enchantment enchantment) {
//if (enchantment instanceof ExcellentEnchant excellentEnchant) {
//ItemUtil.delLore(item, excellentEnchant.getId());
//}
public static void removeEnchantment(@NotNull ItemStack item, @NotNull Enchantment enchantment) {
ItemMeta meta = item.getItemMeta();
if (meta instanceof EnchantmentStorageMeta storageMeta) {
storageMeta.removeStoredEnchant(enchantment);
@ -229,68 +193,103 @@ public class EnchantManager extends AbstractManager<ExcellentEnchants> {
item.setItemMeta(meta);
}
// Too expensive
@NotNull
@Deprecated
public static Map<ExcellentEnchant, Integer> getItemCustomEnchants(@NotNull ItemStack item) {
return EnchantManager.getItemEnchants(item).entrySet().stream()
.filter(entry -> entry.getKey() instanceof ExcellentEnchant)
.map(entry -> new AbstractMap.SimpleEntry<>((ExcellentEnchant) entry.getKey(), entry.getValue()))
.sorted((e1,e2) -> e2.getKey().getPriority().ordinal() - e1.getKey().getPriority().ordinal())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (old, nev) -> nev, LinkedHashMap::new));
}
@SuppressWarnings("unchecked")
@NotNull
public static <T> Map<T, Integer> getItemCustomEnchants(@NotNull ItemStack item, @NotNull Class<T> clazz) {
return EnchantManager.getItemCustomEnchants(item).entrySet().stream()
.filter(entry -> clazz.isAssignableFrom(entry.getKey().getClass()))
.sorted((e1,e2) -> e2.getKey().getPriority().ordinal() - e1.getKey().getPriority().ordinal())
.collect(Collectors.toMap(k -> (T) k.getKey(), Map.Entry::getValue, (old, nev) -> nev, LinkedHashMap::new));
}
@Deprecated
public static int getItemCustomEnchantsAmount(@NotNull ItemStack item) {
return EnchantManager.getItemCustomEnchants(item).size();
}
@Deprecated
public static int getItemEnchantLevel(@NotNull ItemStack item, @NotNull Enchantment enchantment) {
return getItemEnchants(item).getOrDefault(enchantment, 0);
}
@NotNull
@Deprecated
public static Map<Enchantment, Integer> getItemEnchants(@NotNull ItemStack item) {
public static Map<Enchantment, Integer> getEnchantments(@NotNull ItemStack item) {
ItemMeta meta = item.getItemMeta();
if (meta == null) return Collections.emptyMap();
return (meta instanceof EnchantmentStorageMeta meta2) ? meta2.getStoredEnchants() : meta.getEnchants();
}
@Deprecated
public static int getItemEnchantsAmount(@NotNull ItemStack item) {
return EnchantManager.getItemEnchants(item).size();
public static int getEnchantmentsAmount(@NotNull ItemStack item) {
return EnchantManager.getEnchantments(item).size();
}
public static boolean hasEnchantment(@NotNull ItemStack item, @NotNull Enchantment enchantment) {
return getEnchantmentLevel(item, enchantment) > 0;
return EnchantManager.getEnchantmentLevel(item, enchantment) > 0;
}
public static int getEnchantmentLevel(@NotNull ItemStack item, @NotNull Enchantment enchant) {
ItemMeta meta = item.getItemMeta();
if (meta == null) return 0;
return EnchantManager.getEnchantments(item).getOrDefault(enchant, 0);
}
return meta.getEnchantLevel(enchant);
public static int getEnchantmentCharges(@NotNull ItemStack item, @NotNull ExcellentEnchant enchant) {
return PDCUtil.getIntData(item, enchant.getChargesKey());
}
public static boolean isEnchantmentOutOfCharges(@NotNull ItemStack item, @NotNull ExcellentEnchant enchant) {
return enchant.isChargesEnabled() && getEnchantmentCharges(item, enchant) == 0;
}
public static boolean isEnchantmentFullOfCharges(@NotNull ItemStack item, @NotNull ExcellentEnchant enchant) {
if (!enchant.isChargesEnabled()) return true;
int level = getEnchantmentLevel(item, enchant);
int max = enchant.getChargesMax(level);
return EnchantManager.getEnchantmentCharges(item, enchant) == max;
}
public static void consumeEnchantmentCharges(@NotNull ItemStack item, @NotNull ExcellentEnchant enchant) {
if (!enchant.isChargesEnabled()) return;
int level = getEnchantmentLevel(item, enchant);
int has = getEnchantmentCharges(item, enchant);
int use = enchant.getChargesConsumeAmount(level);
EnchantManager.setEnchantmentCharges(item, enchant, has - use);
}
public static void restoreEnchantmentCharges(@NotNull ItemStack item, @NotNull ExcellentEnchant enchant) {
if (!enchant.isChargesEnabled()) return;
int level = getEnchantmentLevel(item, enchant);
int max = enchant.getChargesMax(level);
EnchantManager.setEnchantmentCharges(item, enchant, max);
}
public static void rechargeEnchantmentCharges(@NotNull ItemStack item, @NotNull ExcellentEnchant enchant) {
if (!enchant.isChargesEnabled()) return;
int level = getEnchantmentLevel(item, enchant);
int recharge = enchant.getChargesRechargeAmount(level);
int has = getEnchantmentCharges(item, enchant);
EnchantManager.setEnchantmentCharges(item, enchant, has + recharge);
}
public static void setEnchantmentCharges(@NotNull ItemStack item, @NotNull ExcellentEnchant enchant, int charges) {
if (!enchant.isChargesEnabled()) return;
int level = getEnchantmentLevel(item, enchant);
int max = enchant.getChargesMax(level);
PDCUtil.setData(item, enchant.getChargesKey(), Math.max(0, Math.min(charges, max)));
}
public static int getExcellentEnchantmentsAmount(@NotNull ItemStack item) {
return EnchantManager.getExcellentEnchantments(item).size();
}
@NotNull
public static Map<ExcellentEnchant, Integer> getExcellentEnchantments(@NotNull ItemStack item) {
return EnchantManager.getItemEnchants(item).entrySet().stream()
return EnchantManager.getEnchantments(item).entrySet().stream()
.map(entry -> {
ExcellentEnchant ex = EnchantRegister.get(entry.getKey().getKey());
return ex == null ? null : Pair.of(ex, entry.getValue());
}).filter(Objects::nonNull)
ExcellentEnchant enchant = EnchantRegister.get(entry.getKey().getKey());
return enchant == null ? null : Pair.of(enchant, entry.getValue());
})
.filter(Objects::nonNull)
.sorted(Comparator.comparing(p -> p.getFirst().getPriority(), Comparator.reverseOrder()))
.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (old, nev) -> nev, LinkedHashMap::new));
}
@SuppressWarnings("unchecked")
@NotNull
public static <T extends IEnchantment> Map<T, Integer> getExcellentEnchantments(@NotNull ItemStack item, @NotNull Class<T> clazz) {
return EnchantManager.getEnchantments(item).entrySet().stream()
.map(entry -> {
ExcellentEnchant enchant = EnchantRegister.get(entry.getKey().getKey());
if (enchant == null || !clazz.isAssignableFrom(enchant.getClass())) return null;
return Pair.of((T) enchant, entry.getValue());
})
.filter(Objects::nonNull)
.sorted(Comparator.comparing(p -> p.getFirst().getPriority(), Comparator.reverseOrder()))
.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (old, nev) -> nev, LinkedHashMap::new));
}
@ -311,64 +310,45 @@ public class EnchantManager extends AbstractManager<ExcellentEnchants> {
}
@NotNull
public static Map<ExcellentEnchant, Integer> getEquippedEnchantsMax(@NotNull LivingEntity entity) {
return getEquippedEnchants(entity, Math::max);
}
@NotNull
public static Map<ExcellentEnchant, Integer> getEquippedEnchantsTotal(@NotNull LivingEntity entity) {
return getEquippedEnchants(entity, Integer::sum);
}
@NotNull
private static Map<ExcellentEnchant, Integer> getEquippedEnchants(@NotNull LivingEntity entity, @NotNull BiFunction<Integer, Integer, Integer> remap) {
Map<ExcellentEnchant, Integer> map = new HashMap<>();
public static Map<EquipmentSlot, ItemStack> getEquipmentEnchanted(@NotNull LivingEntity entity) {
Map<EquipmentSlot, ItemStack> equipment = EntityUtil.getEquippedItems(entity);
equipment.entrySet().stream().filter(entry -> {
if (entry.getValue() == null) return false;
if (entry.getValue().getType() == Material.ENCHANTED_BOOK) return false;
if ((entry.getKey() == EquipmentSlot.HAND || entry.getKey() == EquipmentSlot.OFF_HAND) && ItemUtil.isArmor(entry.getValue())) return false;
return true;
}).map(Map.Entry::getValue).map(EnchantManager::getItemCustomEnchants).forEach(itemEnchants -> {
itemEnchants.forEach((enchant, level) -> map.merge(enchant, level, remap));
equipment.entrySet().removeIf(entry -> {
ItemStack item = entry.getValue();
EquipmentSlot slot = entry.getKey();
if (item == null || item.getType().isAir() || item.getType() == Material.ENCHANTED_BOOK) return true;
if ((slot == EquipmentSlot.HAND || slot == EquipmentSlot.OFF_HAND) && ItemUtil.isArmor(item)) return true;
return !item.hasItemMeta();
});
return equipment;
}
@NotNull
public static Map<ItemStack, Map<ExcellentEnchant, Integer>> getEquippedEnchants(@NotNull LivingEntity entity) {
Map<ItemStack, Map<ExcellentEnchant, Integer>> map = new HashMap<>();
EnchantManager.getEquipmentEnchanted(entity).values().forEach(item -> {
map.computeIfAbsent(item, k -> new LinkedHashMap<>()).putAll(EnchantManager.getExcellentEnchantments(item));
});
return map;
}
public static int getEquippedEnchantLevelMax(@NotNull LivingEntity entity, @NotNull ExcellentEnchant enchant) {
return getEquippedEnchantsMax(entity).getOrDefault(enchant, 0);
}
public static int getEquippedEnchantLevelTotal(@NotNull LivingEntity entity, @NotNull ExcellentEnchant enchant) {
return getEquippedEnchantsTotal(entity).getOrDefault(enchant, 0);
@NotNull
public static <T extends IEnchantment> Map<ItemStack, Map<T, Integer>> getEquippedEnchants(@NotNull LivingEntity entity, @NotNull Class<T> clazz) {
Map<ItemStack, Map<T, Integer>> map = new HashMap<>();
EnchantManager.getEquipmentEnchanted(entity).values().forEach(item -> {
map.computeIfAbsent(item, k -> new LinkedHashMap<>()).putAll(EnchantManager.getExcellentEnchantments(item, clazz));
});
return map;
}
public static void updateEquippedEnchantEffects(@NotNull LivingEntity entity) {
getEquippedEnchantsMax(entity).forEach((enchant, level) -> {
if (enchant instanceof PassiveEnchant passiveEnchant && enchant instanceof IEnchantPotionTemplate) {
passiveEnchant.use(entity, level);
}
EnchantManager.getEquippedEnchants(entity, PassiveEnchant.class).forEach((item, enchants) -> {
enchants.forEach((enchant, level) -> {
if (enchant instanceof Potioned potioned) {
if (enchant.onTrigger(entity, item, level)) {
enchant.consumeCharges(item);
}
}
});
});
}
@Nullable
public static EnchantTier getTierById(@NotNull String id) {
return Config.getTierById(id);
}
@NotNull
public static Collection<EnchantTier> getTiers() {
return Config.getTiers();
}
@NotNull
public static List<String> getTierIds() {
return Config.getTierIds();
}
@Nullable
public static EnchantTier getTierByChance(@NotNull ObtainType obtainType) {
return Config.getTierByChance(obtainType);
}
}

View File

@ -1,26 +1,30 @@
package su.nightexpress.excellentenchants.manager.object;
package su.nightexpress.excellentenchants.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.ExcellentEnchantsAPI;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.manager.type.ObtainType;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import su.nightexpress.excellentenchants.tier.Tier;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class EnchantPopulator {
private final ObtainType obtainType;
private final ItemStack item;
private final Map<EnchantTier, Set<ExcellentEnchant>> enchants;
private final ObtainType obtainType;
private final ItemStack item;
private final Map<Tier, Set<ExcellentEnchant>> enchants;
public EnchantPopulator(@NotNull ObtainType obtainType, @NotNull ItemStack item) {
this.obtainType = obtainType;
this.item = item;
this.enchants = Config.getTiers().stream()
this.enchants = ExcellentEnchantsAPI.getTierManager().getTiers().stream()
.collect(Collectors.toMap(k -> k, v -> v.getEnchants(obtainType, item), (prev, add) -> add, HashMap::new));
}
@ -28,15 +32,15 @@ public class EnchantPopulator {
return this.getEnchants().isEmpty() || this.getEnchants().values().stream().allMatch(Set::isEmpty);
}
public boolean isEmpty(@NotNull EnchantTier tier) {
public boolean isEmpty(@NotNull Tier tier) {
return this.getEnchants(tier).isEmpty();
}
public void purge(@NotNull EnchantTier tier) {
public void purge(@NotNull Tier tier) {
this.getEnchants().remove(tier);
}
public void purge(@NotNull EnchantTier tier, @NotNull ExcellentEnchant enchant) {
public void purge(@NotNull Tier tier, @NotNull ExcellentEnchant enchant) {
this.getEnchants(tier).remove(enchant);
this.getEnchants().keySet().removeIf(this::isEmpty);
}
@ -52,24 +56,24 @@ public class EnchantPopulator {
}
@NotNull
public Map<EnchantTier, Set<ExcellentEnchant>> getEnchants() {
public Map<Tier, Set<ExcellentEnchant>> getEnchants() {
return this.enchants;
}
@NotNull
public Set<ExcellentEnchant> getEnchants(@NotNull EnchantTier tier) {
public Set<ExcellentEnchant> getEnchants(@NotNull Tier tier) {
return this.getEnchants().getOrDefault(tier, new HashSet<>());
}
@Nullable
public EnchantTier getTierByChance() {
Map<EnchantTier, Double> map = this.getEnchants().keySet().stream()
public Tier getTierByChance() {
Map<Tier, Double> map = this.getEnchants().keySet().stream()
.collect(Collectors.toMap(k -> k, v -> v.getChance(this.getObtainType())));
return Rnd.get(map);
}
@Nullable
public ExcellentEnchant getEnchantByChance(@NotNull EnchantTier tier) {
public ExcellentEnchant getEnchantByChance(@NotNull Tier tier) {
Map<ExcellentEnchant, Double> map = this.getEnchants(tier).stream()
.collect(Collectors.toMap(k -> k, v -> v.getObtainChance(this.getObtainType())));
return map.isEmpty() ? null : Rnd.get(map);

View File

@ -1,19 +1,19 @@
package su.nightexpress.excellentenchants.manager;
package su.nightexpress.excellentenchants.enchantment;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.manager.ICleanable;
import su.nexmedia.engine.utils.Reflex;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.manager.enchants.armor.*;
import su.nightexpress.excellentenchants.manager.enchants.bow.*;
import su.nightexpress.excellentenchants.manager.enchants.tool.*;
import su.nightexpress.excellentenchants.manager.enchants.weapon.*;
import su.nightexpress.excellentenchants.enchantment.impl.armor.*;
import su.nightexpress.excellentenchants.enchantment.impl.bow.*;
import su.nightexpress.excellentenchants.enchantment.impl.tool.*;
import su.nightexpress.excellentenchants.enchantment.impl.universal.EnchantCurseOfFragility;
import su.nightexpress.excellentenchants.enchantment.impl.weapon.*;
import java.lang.reflect.Field;
import java.util.HashMap;
@ -24,19 +24,19 @@ public class EnchantRegister {
private static final ExcellentEnchants PLUGIN;
public static final Map<NamespacedKey, ExcellentEnchant> ENCHANT_REGISTRY;
public static final EnchantBlastMining BLAST_MINING;
public static final EnchantCurseOfBreaking CURSE_OF_BREAKING;
public static final EnchantBlastMining BLAST_MINING;
public static final EnchantCurseOfBreaking CURSE_OF_BREAKING;
public static final EnchantCurseOfMisfortune CURSE_OF_MISFORTUNE;
public static final EnchantDivineTouch DIVINE_TOUCH;
public static final EnchantHaste HASTE;
public static final EnchantLuckyMiner LUCKY_MINER;
public static final EnchantReplanter REPLANTER;
public static final EnchantSilkChest SILK_CHEST;
public static final EnchantSmelter SMELTER;
public static final EnchantTelekinesis TELEKINESIS;
public static final EnchantTreasures TREASURES;
public static final EnchantTunnel TUNNEL;
public static final EnchantVeinminer VEINMINER;
public static final EnchantDivineTouch DIVINE_TOUCH;
public static final EnchantHaste HASTE;
public static final EnchantLuckyMiner LUCKY_MINER;
public static final EnchantReplanter REPLANTER;
public static final EnchantSilkChest SILK_CHEST;
public static final EnchantSmelter SMELTER;
public static final EnchantTelekinesis TELEKINESIS;
public static final EnchantTreasures TREASURES;
public static final EnchantTunnel TUNNEL;
public static final EnchantVeinminer VEINMINER;
public static final EnchantBaneOfNetherspawn BANE_OF_NETHERSPAWN;
public static final EnchantIceAspect ICE_ASPECT;
@ -45,18 +45,18 @@ public class EnchantRegister {
public static final EnchantExhaust EXHAUST;
public static final EnchantWither WITHER;
public static final EnchantParalyze PARALYZE;
public static final EnchantExpHunter EXP_HUNTER;
public static final EnchantDecapitator DECAPITATOR;
public static final EnchantCutter CUTTER;
public static final EnchantExpHunter EXP_HUNTER;
public static final EnchantDecapitator DECAPITATOR;
public static final EnchantCutter CUTTER;
public static final EnchantConfusion CONFUSION;
public static final EnchantDoubleStrike DOUBLE_STRIKE;
public static final EnchantNimble NIMBLE;
public static final EnchantNimble NIMBLE;
public static final EnchantBlindness BLINDNESS;
public static final EnchantVampire VAMPIRE;
public static final EnchantCure CURE;
public static final EnchantRage RAGE;
public static final EnchantScavenger SCAVENGER;
public static final EnchantSurprise SURPRISE;
public static final EnchantVampire VAMPIRE;
public static final EnchantCure CURE;
public static final EnchantRage RAGE;
public static final EnchantScavenger SCAVENGER;
public static final EnchantSurprise SURPRISE;
public static final EnchantTemper TEMPER;
public static final EnchantThrifty THRIFTY;
public static final EnchantThunder THUNDER;
@ -64,28 +64,31 @@ public class EnchantRegister {
public static final EnchantRocket ROCKET;
public static final EnchantElementalProtection ELEMENTAL_PROTECTION;
public static final EnchantFireShield FIRE_SHIELD;
public static final EnchantFlameWalker FLAME_WALKER;
public static final EnchantHardened HARDENED;
public static final EnchantColdSteel COLD_STEEL;
public static final EnchantSelfDestruction SELF_DESTRUCTION;
public static final EnchantSaturation SATURATION;
public static final EnchantAquaman AQUAMAN;
public static final EnchantNightVision NIGHT_VISION;
public static final EnchantBunnyHop BUNNY_HOP;
public static final EnchantSonic SONIC;
public static final EnchantRegrowth REGROWTH;
public static final EnchantFireShield FIRE_SHIELD;
public static final EnchantFlameWalker FLAME_WALKER;
public static final EnchantHardened HARDENED;
public static final EnchantIceShield ICE_SHIELD;
public static final EnchantColdSteel COLD_STEEL;
public static final EnchantSelfDestruction SELF_DESTRUCTION;
public static final EnchantSaturation SATURATION;
public static final EnchantAquaman AQUAMAN;
public static final EnchantNightVision NIGHT_VISION;
public static final EnchantBunnyHop BUNNY_HOP;
public static final EnchantSonic SONIC;
public static final EnchantRegrowth REGROWTH;
public static final EnchantBomber BOMBER;
public static final EnchantConfusingArrows CONFUSING_ARROWS;
public static final EnchantDragonfireArrows DRAGONFIRE_ARROWS;
public static final EnchantBomber BOMBER;
public static final EnchantConfusingArrows CONFUSING_ARROWS;
public static final EnchantDragonfireArrows DRAGONFIRE_ARROWS;
public static final EnchantElectrifiedArrows ELECTRIFIED_ARROWS;
public static final EnchantEnderBow ENDER_BOW;
public static final EnchantGhast GHAST;
public static final EnchantHover HOVER;
public static final EnchantPoisonedArrows POISONED_ARROWS;
public static final EnchantWitheredArrows WITHERED_ARROWS;
public static final EnchantExplosiveArrows EXPLOSIVE_ARROWS;
public static final EnchantEnderBow ENDER_BOW;
public static final EnchantGhast GHAST;
public static final EnchantHover HOVER;
public static final EnchantPoisonedArrows POISONED_ARROWS;
public static final EnchantWitheredArrows WITHERED_ARROWS;
public static final EnchantExplosiveArrows EXPLOSIVE_ARROWS;
public static final EnchantCurseOfFragility CURSE_OF_FRAGILITY;
static {
PLUGIN = ExcellentEnchants.getPlugin(ExcellentEnchants.class);
@ -137,6 +140,7 @@ public class EnchantRegister {
AQUAMAN = init(EnchantAquaman.class, EnchantAquaman.ID);
BUNNY_HOP = init(EnchantBunnyHop.class, EnchantBunnyHop.ID);
COLD_STEEL = init(EnchantColdSteel.class, EnchantColdSteel.ID);
ICE_SHIELD = init(EnchantIceShield.class, EnchantIceShield.ID);
ELEMENTAL_PROTECTION = init(EnchantElementalProtection.class, EnchantElementalProtection.ID);
FIRE_SHIELD = init(EnchantFireShield.class, EnchantFireShield.ID);
FLAME_WALKER = init(EnchantFlameWalker.class, EnchantFlameWalker.ID);
@ -159,6 +163,8 @@ public class EnchantRegister {
POISONED_ARROWS = init(EnchantPoisonedArrows.class, EnchantPoisonedArrows.ID);
WITHERED_ARROWS = init(EnchantWitheredArrows.class, EnchantWitheredArrows.ID);
// Universal
CURSE_OF_FRAGILITY = init(EnchantCurseOfFragility.class, EnchantCurseOfFragility.ID);
}
public static void setup() {
@ -168,15 +174,12 @@ public class EnchantRegister {
return;
}
//ENCHANT_LIST.clear();
Reflex.setFieldValue(Enchantment.class, "acceptingNew", true);
for (Field field : EnchantRegister.class.getFields()) {
if (!ExcellentEnchant.class.isAssignableFrom(field.getType())) continue;
ExcellentEnchant enchant;
try {
enchant = (ExcellentEnchant) field.get(null);
ExcellentEnchant enchant = (ExcellentEnchant) field.get(null);
EnchantRegister.register(enchant);
}
catch (Exception e) {
@ -185,7 +188,7 @@ public class EnchantRegister {
}
Enchantment.stopAcceptingRegistrations();
PLUGIN.info("Enchants Registered: " + ENCHANT_REGISTRY.size());
PLUGIN.info("Enchantments Registered: " + ENCHANT_REGISTRY.size());
ExcellentEnchants.isLoaded = true;
}
@ -218,14 +221,12 @@ public class EnchantRegister {
@Nullable
private static <T extends ExcellentEnchant> T init(@NotNull Class<T> clazz, @NotNull String id) {
String enchantId = id.toLowerCase();
if (Config.ENCHANTMENTS_DISABLED.contains(id)) return null;
if (Config.ENCHANTMENTS_DISABLED.get().contains(id)) return null;
JYML enchantCfg = JYML.loadOrExtract(PLUGIN, "/enchants/" + enchantId + ".yml");
try {
return clazz.getConstructor(ExcellentEnchants.class, JYML.class).newInstance(PLUGIN, enchantCfg);
return clazz.getConstructor(ExcellentEnchants.class).newInstance(PLUGIN);
}
catch (ReflectiveOperationException ex) {
catch (Exception ex) {
ex.printStackTrace();
return null;
}
@ -236,8 +237,9 @@ public class EnchantRegister {
Enchantment.registerEnchantment(enchant);
ENCHANT_REGISTRY.put(enchant.getKey(), enchant);
enchant.loadConfig();
enchant.getConfig().saveChanges();
enchant.registerListeners();
PLUGIN.info("Registered enchantment: " + enchant.getId());
//IRegistry.a(IRegistry.ENCHANTMENT, enchant.getId(), CraftEnchantment.getRaw(enchant));
}
}

View File

@ -0,0 +1,30 @@
package su.nightexpress.excellentenchants.enchantment.config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class EnchantScaler extends Scaler {
public EnchantScaler(@NotNull ExcellentEnchant enchant, @NotNull String path) {
super(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);
}
}

View File

@ -0,0 +1,33 @@
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.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
public class EnchantAquaman extends PotionEnchant implements PassiveEnchant {
public static final String ID = "aquaman";
public EnchantAquaman(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.WATER_BREATHING, true);
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_HEAD;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(entity) || this.hasEffect(entity)) return false;
return this.addEffect(entity, level);
}
}

View File

@ -0,0 +1,33 @@
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.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
public class EnchantBunnyHop extends PotionEnchant implements PassiveEnchant {
public static final String ID = "bunny_hop";
public EnchantBunnyHop(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.JUMP, true);
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_FEET;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(entity) || this.hasEffect(entity)) return false;
return this.addEffect(entity, level);
}
}

View File

@ -0,0 +1,56 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantColdSteel extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "cold_steel";
private ChanceImplementation chanceImplementation;
public EnchantColdSteel(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.SLOW_DIGGING, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_TORSO;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
return this.addEffect(damager, level);
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.armor;
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
@ -7,55 +7,57 @@ 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.JYML;
import su.nexmedia.engine.utils.ArrayUtil;
import su.nexmedia.engine.utils.EntityUtil;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.Set;
import java.util.function.UnaryOperator;
public class EnchantElementalProtection extends IEnchantChanceTemplate {
public class EnchantElementalProtection extends ExcellentEnchant {
public static final String ID = "elemental_protection";
public static final String PLACEHOLDER_PROTECTION_AMOUNT = "%enchantment_protection_amount%";
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%";
private static final EntityDamageEvent.DamageCause[] DAMAGE_CAUSES = new EntityDamageEvent.DamageCause[] {
private static final Set<EntityDamageEvent.DamageCause> DAMAGE_CAUSES = Set.of(
EntityDamageEvent.DamageCause.POISON, EntityDamageEvent.DamageCause.WITHER,
EntityDamageEvent.DamageCause.MAGIC, EntityDamageEvent.DamageCause.FREEZE,
/*EntityDamageEvent.DamageCause.SONIC_BOOM, */EntityDamageEvent.DamageCause.LIGHTNING,
};
EntityDamageEvent.DamageCause.LIGHTNING);
private Scaler protectionAmount;
private double protectionCapacity;
private boolean protectionAsModifier;
private EnchantScaler protectionAmount;
private double protectionCapacity;
private boolean protectionAsModifier;
public EnchantElementalProtection(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
public EnchantElementalProtection(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_PROTECTION_AMOUNT, NumberUtil.format(this.getProtectionAmount(level)))
.replace(PLACEHOLDER_PROTECTION_CAPACITY, NumberUtil.format(this.getProtectionCapacity()))
);
;
}
@Override
public void loadConfig() {
super.loadConfig();
this.protectionAmount = new EnchantScaler(this, "Settings.Protection.Amount");
this.protectionCapacity = cfg.getDouble("Settings.Protection.Capacity");
this.protectionAsModifier = cfg.getBoolean("Settings.Protection.As_Modifier");
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);
}
@NotNull
@ -78,22 +80,20 @@ public class EnchantElementalProtection extends IEnchantChanceTemplate {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onDamage(EntityDamageEvent e) {
if (!ArrayUtil.contains(DAMAGE_CAUSES, e.getCause())) return;
if (!(e.getEntity() instanceof LivingEntity victim)) return;
if (!this.isEnchantmentAvailable(victim)) return;
if (!DAMAGE_CAUSES.contains(e.getCause())) return;
if (!(e.getEntity() instanceof LivingEntity entity)) return;
if (!this.isAvailableToUse(entity)) return;
double protectionAmount = 0D;
for (ItemStack armor : EntityUtil.getEquippedArmor(victim).values()) {
if (armor == null || armor.getType().isAir()) continue;
for (ItemStack armor : EnchantManager.getEquipmentEnchanted(entity).values()) {
int level = EnchantManager.getEnchantmentLevel(armor, this);
if (level <= 0) continue;
int level = EnchantManager.getItemEnchantLevel(armor, this);
if (this.checkTriggerChance(level)) {
protectionAmount += this.getProtectionAmount(level);
}
protectionAmount += this.getProtectionAmount(level);
this.consumeCharges(armor);
}
if (protectionAmount <= 0D) return;
if (!this.takeCostItem(victim)) return;
if (protectionAmount <= 0D) return;
if (protectionAmount > this.getProtectionCapacity()) {
protectionAmount = this.getProtectionCapacity();
}

View File

@ -0,0 +1,86 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantFireShield extends ExcellentEnchant implements Chanced, CombatEnchant {
public static final String ID = "fire_shield";
public static final String PLACEHOLDER_FIRE_DURATION = "%enchantment_fire_duration%";
private EnchantScaler fireDuration;
private ChanceImplementation chanceImplementation;
public EnchantFireShield(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_FIRE_DURATION, NumberUtil.format(this.getFireDuration(level)))
;
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
this.fireDuration = EnchantScaler.read(this, "Settings.Fire.Duration", "2.5 * " + Placeholders.ENCHANTMENT_LEVEL,
"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.");
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR;
}
public double getFireDuration(int level) {
return this.fireDuration.getValue(level);
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e,
@NotNull LivingEntity damager, @NotNull LivingEntity victim,
@NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(victim)) return false;
if (!this.checkTriggerChance(level)) return false;
int ticksToSet = (int) (this.getFireDuration(level) * 20);
int ticksHas = damager.getFireTicks();
if (ticksHas >= ticksToSet) return false;
damager.setFireTicks(ticksToSet);
return true;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.armor;
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.Location;
import org.bukkit.Material;
@ -16,36 +16,32 @@ 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.api.config.JYML;
import su.nexmedia.engine.api.manager.ICleanable;
import su.nexmedia.engine.api.task.AbstractTask;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.type.MoveEnchant;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
public class EnchantFlameWalker extends IEnchantChanceTemplate implements MoveEnchant, ICleanable {
public class EnchantFlameWalker extends ExcellentEnchant implements ICleanable {
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, Long> BLOCKS_TO_DESTROY = new HashMap<>();
private static final BlockFace[] FACES = {BlockFace.SOUTH, BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST};
private static final Map<Block, Long> BLOCKS_TO_DESTROY = new ConcurrentHashMap<>();
private Scaler blockDecayTime;
private EnchantScaler blockDecayTime;
private BlockTickTask blockTickTask;
public EnchantFlameWalker(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
public EnchantFlameWalker(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
this.blockTickTask = new BlockTickTask(plugin);
this.blockTickTask.start();
@ -54,14 +50,8 @@ public class EnchantFlameWalker extends IEnchantChanceTemplate implements MoveEn
@Override
public void loadConfig() {
super.loadConfig();
this.blockDecayTime = new EnchantScaler(this, "Settings.Block_Decay");
}
@Override
protected void updateConfig() {
super.updateConfig();
cfg.addMissing("Settings.Block_Decay", "5.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 2");
this.blockDecayTime = EnchantScaler.read(this, "Settings.Block_Decay", "12.0",
"Sets up to how long (in seconds) blocks will stay before turn back to lava.");
}
@Override
@ -88,23 +78,10 @@ public class EnchantFlameWalker extends IEnchantChanceTemplate implements MoveEn
return this.blockDecayTime.getValue(level);
}
@Override
public boolean use(@NotNull PlayerMoveEvent e, @NotNull LivingEntity entity, int level) {
if (!this.isEnchantmentAvailable(entity)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(entity)) return false;
plugin.getEnchantNMS().handleFlameWalker(entity, entity.getLocation(), level).forEach(block -> {
addBlock(block, Rnd.getDouble(this.getBlockDecayTime(level)) + 1);
});
return true;
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onEnchantFlameWalker(PlayerMoveEvent e) {
public void onPlayerMove(PlayerMoveEvent e) {
Player player = e.getPlayer();
if (player.isFlying()) return;
if (!this.isEnchantmentAvailable(player)) return;
if (player.isFlying() || !this.isAvailableToUse(player)) return;
Location from = e.getFrom();
Location to = e.getTo();
@ -114,15 +91,16 @@ public class EnchantFlameWalker extends IEnchantChanceTemplate implements MoveEn
ItemStack boots = player.getInventory().getBoots();
if (boots == null || boots.getType().isAir()) return;
//int level = boots.getEnchantmentLevel(this);
int level = EnchantManager.getEnchantmentLevel(boots, this);
if (level < 1) return;
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;
this.use(e, player, level);
plugin.getEnchantNMS().handleFlameWalker(player, player.getLocation(), level).forEach(block -> {
addBlock(block, Rnd.getDouble(this.getBlockDecayTime(level)) + 1);
});
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -135,10 +113,10 @@ public class EnchantFlameWalker extends IEnchantChanceTemplate implements MoveEn
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onFlameWalkerMagmaDamage(EntityDamageEvent e) {
public void onMagmaDamage(EntityDamageEvent e) {
if (e.getCause() != EntityDamageEvent.DamageCause.HOT_FLOOR) return;
if (!(e.getEntity() instanceof LivingEntity livingEntity)) return;
if (!this.isEnchantmentAvailable(livingEntity)) return;
if (!this.isAvailableToUse(livingEntity)) return;
EntityEquipment equipment = livingEntity.getEquipment();
if (equipment == null) return;
@ -147,8 +125,7 @@ public class EnchantFlameWalker extends IEnchantChanceTemplate implements MoveEn
if (boots == null || boots.getType().isAir()) return;
int level = EnchantManager.getEnchantmentLevel(boots, this);
if (level < 1) return;
if (!this.checkTriggerChance(level)) return;
if (level <= 0) return;
e.setCancelled(true);
}
@ -169,7 +146,7 @@ public class EnchantFlameWalker extends IEnchantChanceTemplate implements MoveEn
long time = BLOCKS_TO_DESTROY.get(block);
if (now >= time) {
block.setType(Material.LAVA);
EffectUtil.playEffect(block.getLocation(), Particle.BLOCK_CRACK.name(), Material.MAGMA_BLOCK.name(), 0.5, 0.7, 0.5, 0.03, 50);
EffectUtil.playEffect(block.getLocation(), Particle.BLOCK_CRACK, Material.MAGMA_BLOCK.name(), 0.5, 0.7, 0.5, 0.03, 50);
return true;
}
return false;

View File

@ -0,0 +1,56 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantHardened extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "hardened";
private ChanceImplementation chanceImplementation;
public EnchantHardened(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.DAMAGE_RESISTANCE, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_TORSO;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
return this.addEffect(victim, level);
}
}

View File

@ -0,0 +1,65 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantIceShield extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "ice_shield";
private ChanceImplementation chanceImplementation;
public EnchantIceShield(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.SLOW, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_TORSO;
}
@Override
@NotNull
public Chanced getChanceImplementation() {
return this.chanceImplementation;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(victim)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.addEffect(damager, level)) return false;
damager.setFreezeTicks(damager.getMaxFreezeTicks());
if (this.hasVisualEffects()) {
EffectUtil.playEffect(damager.getEyeLocation(), Particle.BLOCK_CRACK, Material.ICE.name(), 0.25, 0.25, 0.25, 0.1f, 15);
}
return true;
}
}

View File

@ -0,0 +1,33 @@
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.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
public class EnchantNightVision extends PotionEnchant implements PassiveEnchant {
public static final String ID = "night_vision";
public EnchantNightVision(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.NIGHT_VISION, true);
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_HEAD;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(entity) || this.hasEffect(entity)) return false;
return this.addEffect(entity, level);
}
}

View File

@ -0,0 +1,134 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.Particle;
import org.bukkit.attribute.Attribute;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.api.manager.ICleanable;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.EntityUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.task.AbstractEnchantmentTask;
import java.util.function.UnaryOperator;
public class EnchantRegrowth extends ExcellentEnchant implements PassiveEnchant, ICleanable {
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 static final String PLACEHOLDER_HEAL_INTERVAL = "%enchantment_heal_interval%";
private long healInterval;
private EnchantScaler healMinHealth;
private EnchantScaler healMaxHealth;
private EnchantScaler healAmount;
private Task task;
public EnchantRegrowth(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
this.task = new Task(plugin);
this.task.start();
}
@Override
public void loadConfig() {
super.loadConfig();
this.healInterval = JOption.create("Settings.Heal.Interval", 100,
"How often (in seconds) enchantment will have effect?").read(cfg);
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.");
}
@Override
public void clear() {
if (this.task != null) {
this.task.stop();
this.task = null;
}
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_HEAL_AMOUNT, NumberUtil.format(this.getHealAmount(level)))
.replace(PLACEHOLDER_HEAL_MIN_HEALTH, NumberUtil.format(this.getHealMaxHealth(level)))
.replace(PLACEHOLDER_HEAL_MAX_HEALTH, NumberUtil.format(this.getHealMaxHealth(level)))
.replace(PLACEHOLDER_HEAL_INTERVAL, NumberUtil.format((double) this.healInterval / 20D))
;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_TORSO;
}
public double getHealAmount(int level) {
return this.healAmount.getValue(level);
}
public double getHealMinHealth(int level) {
return this.healMinHealth.getValue(level);
}
public double getHealMaxHealth(int level) {
return this.healMaxHealth.getValue(level);
}
public long getHealInterval() {
return this.healInterval;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(entity)) return false;
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 >= healthMax) return false;
double amount = Math.min(healthMax, healthHas + this.getHealAmount(level));
entity.setHealth(amount);
if (this.hasVisualEffects()) {
EffectUtil.playEffect(entity.getEyeLocation(), Particle.HEART, "", 0.3, 0.3, 0.3, 0.1, 5);
}
return true;
}
class Task extends AbstractEnchantmentTask {
public Task(@NotNull ExcellentEnchants plugin) {
super(plugin, healInterval, false);
}
@Override
public void action() {
for (LivingEntity entity : this.getEntities()) {
EnchantManager.getEquippedEnchants(entity, EnchantRegrowth.class).forEach((item, enchants) -> {
enchants.forEach((enchant, level) -> enchant.onTrigger(entity, item, level));
});
}
}
}
}

View File

@ -0,0 +1,117 @@
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.api.manager.ICleanable;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.task.AbstractEnchantmentTask;
import java.util.function.UnaryOperator;
public class EnchantSaturation extends ExcellentEnchant implements PassiveEnchant, ICleanable {
public static final String ID = "saturation";
private static final String PLACEHOLDER_SATURATION_AMOUNT = "%enchantment_saturation_amount%";
private static final String PLACEHOLDER_SATURATION_INTERVAL = "%enchantment_saturation_interval%";
private static final String PLACEHOLDER_SATURATION_MAX_FOOD_LEVEL = "%enchantment_saturation_max_food_level%";
private long saturationInterval;
private EnchantScaler saturationAmount;
private EnchantScaler saturationMaxFoodLevel;
private Task task;
public EnchantSaturation(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
this.task = new Task(plugin);
this.task.start();
}
@Override
public void loadConfig() {
super.loadConfig();
this.saturationInterval = JOption.create("Settings.Saturation.Interval", 100,
"How often (in seconds) enchantment will have effect?").read(cfg);
this.saturationAmount = EnchantScaler.read(this, "Settings.Saturation.Amount", Placeholders.ENCHANTMENT_LEVEL,
"Amount of food points to restore.");
this.saturationMaxFoodLevel = EnchantScaler.read(this, "Settings.Saturation.Max_Food_Level", "20",
"Maximal player's food level for the enchantment to stop feeding them.");
}
@Override
public void clear() {
if (this.task != null) {
this.task.stop();
this.task = null;
}
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_SATURATION_AMOUNT, NumberUtil.format(this.getSaturationAmount(level)))
.replace(PLACEHOLDER_SATURATION_INTERVAL, NumberUtil.format((double) this.saturationInterval / 20D))
.replace(PLACEHOLDER_SATURATION_MAX_FOOD_LEVEL, NumberUtil.format(this.getMaxFoodLevel(level)))
;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_HEAD;
}
public final int getSaturationAmount(int level) {
return (int) this.saturationAmount.getValue(level);
}
public final int getMaxFoodLevel(int level) {
return (int) this.saturationMaxFoodLevel.getValue(level);
}
public long getSaturationInterval() {
return saturationInterval;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(entity)) return false;
if (!(entity instanceof Player player)) return false;
if (player.getFoodLevel() >= this.getMaxFoodLevel(level)) return false;
int amount = this.getSaturationAmount(level);
player.setFoodLevel(Math.min(20, player.getFoodLevel() + amount));
player.setSaturation(Math.min(20, player.getSaturation() + amount));
return true;
}
class Task extends AbstractEnchantmentTask {
public Task(@NotNull ExcellentEnchants plugin) {
super(plugin, saturationInterval, false);
}
@Override
public void action() {
for (LivingEntity entity : this.getEntities()) {
EnchantManager.getEquippedEnchants(entity, EnchantSaturation.class).forEach((item, enchants) -> {
enchants.forEach((enchant, level) -> enchant.onTrigger(entity, item, level));
});
}
}
}
}

View File

@ -1,49 +1,61 @@
package su.nightexpress.excellentenchants.manager.enchants.armor;
package su.nightexpress.excellentenchants.enchantment.impl.armor;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantSelfDestruction extends IEnchantChanceTemplate implements DeathEnchant {
private Scaler explosionSize;
public class EnchantSelfDestruction extends ExcellentEnchant implements Chanced, DeathEnchant {
public static final String ID = "self_destruction";
private static final String META_EXPLOSION_SOURCE = ID + "_explosion_source";
private static final String META_EXPLOSION_SOURCE = ID + "_explosion_source";
private static final String PLACEHOLDER_EXPLOSION_POWER = "%enchantment_explosion_power%";
public EnchantSelfDestruction(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
private EnchantScaler explosionSize;
private ChanceImplementation chanceImplementation;
public EnchantSelfDestruction(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.explosionSize = new EnchantScaler(this, "Settings.Explosion.Size");
this.chanceImplementation = ChanceImplementation.create(this);
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.");
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_EXPLOSION_POWER, NumberUtil.format(this.getExplosionSize(level)))
);
;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@ -57,18 +69,22 @@ public class EnchantSelfDestruction extends IEnchantChanceTemplate implements De
}
@Override
public boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level) {
if (!this.isEnchantmentAvailable(dead)) return false;
public boolean onDeath(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, int level) {
if (!this.isAvailableToUse(entity)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(dead)) return false;
float size = (float) this.getExplosionSize(level);
dead.setMetadata(META_EXPLOSION_SOURCE, new FixedMetadataValue(plugin, true));
boolean exploded = dead.getWorld().createExplosion(dead.getLocation(), size, false, false, dead);
dead.removeMetadata(META_EXPLOSION_SOURCE, plugin);
entity.setMetadata(META_EXPLOSION_SOURCE, new FixedMetadataValue(plugin, true));
boolean exploded = entity.getWorld().createExplosion(entity.getLocation(), size, false, false, entity);
entity.removeMetadata(META_EXPLOSION_SOURCE, plugin);
return exploded;
}
@Override
public boolean onKill(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, @NotNull Player killer, int level) {
return false;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemDamage(EntityDamageByEntityEvent e) {
if (!e.getDamager().hasMetadata(META_EXPLOSION_SOURCE)) return;

View File

@ -0,0 +1,33 @@
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.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
public class EnchantSonic extends PotionEnchant implements PassiveEnchant {
public static final String ID = "sonic";
public EnchantSonic(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.SPEED, true);
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.ARMOR_FEET;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(entity) || this.hasEffect(entity)) return false;
return this.addEffect(entity, level);
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.bow;
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
@ -9,48 +9,49 @@ 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.JYML;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantBomber extends IEnchantChanceTemplate implements BowEnchant {
private Scaler fuseTicks;
public class EnchantBomber extends ExcellentEnchant implements Chanced, BowEnchant {
public static final String ID = "bomber";
public static final String PLACEHOLDER_FUSE_TICKS = "%enchantment_fuse_ticks%";
public EnchantBomber(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.HIGHEST);
private EnchantScaler fuseTicks;
private ChanceImplementation chanceImplementation;
public EnchantBomber(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.HIGHEST);
}
@Override
public void loadConfig() {
super.loadConfig();
this.fuseTicks = new EnchantScaler(this, "Settings.Fuse_Ticks");
}
@Override
protected void updateConfig() {
super.updateConfig();
this.cfg.addMissing("Settings.Fuse_Ticks", "100 - %enchantment_level% * 10");
this.chanceImplementation = ChanceImplementation.create(this);
this.fuseTicks = EnchantScaler.read(this, "Settings.Fuse_Ticks", "100 - " + Placeholders.ENCHANTMENT_LEVEL + " * 10",
"Sets fuse ticks (before it will explode) for the launched TNT.");
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
.replace(PLACEHOLDER_FUSE_TICKS, NumberUtil.format((double) this.getFuseTicks(level) / 20D))
);
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_FUSE_TICKS, NumberUtil.format((double) this.getFuseTicks(level) / 20D));
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public int getFuseTicks(int level) {
@ -64,11 +65,10 @@ public class EnchantBomber extends IEnchantChanceTemplate implements BowEnchant
}
@Override
public boolean use(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isEnchantmentAvailable(shooter)) return false;
public boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!(e.getProjectile() instanceof Projectile projectile)) return false;
if (!EnchantManager.hasEnchantment(bow, ARROW_INFINITE) && !this.takeCostItem(shooter)) return false;
TNTPrimed primed = projectile.getWorld().spawn(projectile.getLocation(), TNTPrimed.class);
primed.setVelocity(projectile.getVelocity().multiply(e.getForce() * 1.25));
@ -79,12 +79,12 @@ public class EnchantBomber extends IEnchantChanceTemplate implements BowEnchant
}
@Override
public boolean use(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,76 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.enchantments.EnchantmentTarget;
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.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantConfusingArrows extends PotionEnchant implements Chanced, Arrowed, BowEnchant {
public static final String ID = "confusing_arrows";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
public EnchantConfusingArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.CONFUSION, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.arrowImplementation = ArrowImplementation.create(this);
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
if (!(e.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return this.isOurProjectile(projectile);
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return this.isOurProjectile(projectile);
}
}

View File

@ -0,0 +1,133 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Location;
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.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.inventory.ItemStack;
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.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
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.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
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, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.arrowImplementation = ArrowImplementation.create(this);
this.chanceImplementation = ChanceImplementation.create(this);
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.");
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_FIRE_DURATION, NumberUtil.format(this.getFireDuration(level) / 20D))
.replace(PLACEHOLDER_FIRE_RADIUS, NumberUtil.format(this.getFireRadius(level)))
;
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
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 e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (!this.isOurProjectile(projectile)) return false;
if (e.getHitEntity() != null) return false;
this.createCloud(projectile.getShooter(), projectile.getLocation() , level);
return true;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @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 true;
}
private void createCloud(@Nullable ProjectileSource shooter, @NotNull Location location, int level) {
World world = location.getWorld();
if (world == null) return;
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);
}
}

View File

@ -0,0 +1,92 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.Particle;
import org.bukkit.block.Block;
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.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.LocationUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
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.api.enchantment.util.EnchantPriority;
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 ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
public EnchantElectrifiedArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.arrowImplementation = ArrowImplementation.create(this);
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (!this.isOurProjectile(projectile)) return false;
if (e.getHitEntity() != null || e.getHitBlock() == null) return false;
Block block = e.getHitBlock();
block.getWorld().strikeLightning(block.getLocation());
if (this.hasVisualEffects()) {
EffectUtil.playEffect(LocationUtil.getCenter(block.getLocation()), Particle.BLOCK_CRACK, block.getType().name(), 1D, 1D, 1D, 0.05, 150);
EffectUtil.playEffect(LocationUtil.getCenter(block.getLocation()), Particle.FIREWORKS_SPARK, "", 1D, 1D, 1D, 0.05, 150);
}
return true;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @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, () -> {
victim.setNoDamageTicks(0);
victim.getWorld().strikeLightning(victim.getLocation());
});
return true;
}
}

View File

@ -0,0 +1,51 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.EnderPearl;
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.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
public class EnchantEnderBow extends ExcellentEnchant implements BowEnchant {
public static final String ID = "ender_bow";
public EnchantEnderBow(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.HIGHEST);
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
if (!(e.getProjectile() instanceof Projectile projectile)) return false;
EnderPearl pearl = shooter.launchProjectile(EnderPearl.class);
pearl.setVelocity(projectile.getVelocity());
e.setProjectile(pearl);
return true;
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,145 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.World;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
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.EntityDamageEvent;
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.api.config.JOption;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
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.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
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 static final String META_EXPLOSION_SOURCE = ID + "_source";
private boolean explosionFireSpread;
private boolean explosionDamageItems;
private boolean explosionDamageBlocks;
private EnchantScaler explosionSize;
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
public EnchantExplosiveArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.arrowImplementation = ArrowImplementation.create(this);
this.chanceImplementation = ChanceImplementation.create(this);
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.");
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_EXPLOSION_POWER, NumberUtil.format(this.getExplosionSize(level)))
;
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
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 e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
return this.checkTriggerChance(level);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
if (!this.isOurProjectile(projectile)) return false;
Entity shooter = null;
if (projectile.getShooter() instanceof Entity entity) {
shooter = entity;
shooter.setMetadata(META_EXPLOSION_SOURCE, new FixedMetadataValue(this.plugin, true));
}
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, shooter);
if (shooter != null) shooter.removeMetadata(META_EXPLOSION_SOURCE, this.plugin);
return exploded;
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return this.isOurProjectile(projectile);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemDamage(EntityDamageByEntityEvent e) {
if (e.getCause() != EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) return;
if (this.explosionDamageItems) return;
if (!e.getDamager().hasMetadata(META_EXPLOSION_SOURCE)) return;
if (!(e.getEntity() instanceof Item item)) return;
e.setCancelled(true);
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.bow;
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.enchantments.EnchantmentTarget;
@ -11,40 +11,33 @@ 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.JYML;
import su.nexmedia.engine.utils.Scaler;
import su.nexmedia.engine.api.config.JOption;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
public class EnchantGhast extends IEnchantChanceTemplate implements BowEnchant {
private boolean fireSpread;
private Scaler yield;
public class EnchantGhast extends ExcellentEnchant implements BowEnchant {
public static final String ID = "ghast";
public EnchantGhast(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.HIGHEST);
private boolean fireSpread;
private EnchantScaler yield;
public EnchantGhast(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.HIGHEST);
}
@Override
public void loadConfig() {
super.loadConfig();
this.fireSpread = cfg.getBoolean("Settings.Fire_Spread");
this.yield = new EnchantScaler(this, "Settings.Yield");
}
@Override
protected void updateConfig() {
super.updateConfig();
cfg.addMissing("Settings.Fire_Spread", true);
cfg.addMissing("Settings.Yield", "1.0 * " + Placeholders.ENCHANTMENT_LEVEL);
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,
"Fireball explosion size/radius. The more value = the bigger the explosion.");
}
public boolean isFireSpread() {
@ -62,11 +55,9 @@ public class EnchantGhast extends IEnchantChanceTemplate implements BowEnchant {
}
@Override
public boolean use(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isEnchantmentAvailable(shooter)) return false;
if (!this.checkTriggerChance(level)) return false;
public boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
if (!(e.getProjectile() instanceof Projectile projectile)) return false;
if (!EnchantManager.hasEnchantment(bow, ARROW_INFINITE) && !this.takeCostItem(shooter)) return false;
Fireball fireball;
@ -88,18 +79,14 @@ public class EnchantGhast extends IEnchantChanceTemplate implements BowEnchant {
}
@Override
public boolean use(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return false;
}
@Override
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
// Support for the 'Power' enchantment.
int power = EnchantManager.getEnchantmentLevel(weapon, Enchantment.ARROW_DAMAGE);
if (power < 1) return false;
double damagePower = 0.5 + power * 0.5;
e.setDamage(e.getDamage() + damagePower);
return true;
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile,
@NotNull LivingEntity shooter, @NotNull LivingEntity victim,
@NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,76 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.enchantments.EnchantmentTarget;
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.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantHover extends PotionEnchant implements Chanced, Arrowed, BowEnchant {
public static final String ID = "hover";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
public EnchantHover(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.LEVITATION, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.arrowImplementation = ArrowImplementation.create(this);
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
if (!(e.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return this.isOurProjectile(projectile);
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return this.isOurProjectile(projectile);
}
}

View File

@ -0,0 +1,76 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.enchantments.EnchantmentTarget;
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.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantPoisonedArrows extends PotionEnchant implements Chanced, Arrowed, BowEnchant {
public static final String ID = "poisoned_arrows";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
public EnchantPoisonedArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.POISON, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.arrowImplementation = ArrowImplementation.create(this);
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
if (!(e.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return this.isOurProjectile(projectile);
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return this.isOurProjectile(projectile);
}
}

View File

@ -0,0 +1,76 @@
package su.nightexpress.excellentenchants.enchantment.impl.bow;
import org.bukkit.enchantments.EnchantmentTarget;
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.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantWitheredArrows extends PotionEnchant implements Chanced, Arrowed, BowEnchant {
public static final String ID = "withered_arrows";
private ArrowImplementation arrowImplementation;
private ChanceImplementation chanceImplementation;
public EnchantWitheredArrows(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.WITHER, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.arrowImplementation = ArrowImplementation.create(this);
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ArrowImplementation getArrowImplementation() {
return arrowImplementation;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BOW;
}
@Override
public boolean onShoot(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
if (!this.isAvailableToUse(shooter)) return false;
if (!(e.getProjectile() instanceof Arrow arrow)) return false;
if (!this.checkTriggerChance(level)) return false;
return arrow.addCustomEffect(this.createEffect(level), true);
}
@Override
public boolean onHit(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
return this.isOurProjectile(projectile);
}
@Override
public boolean onDamage(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return this.isOurProjectile(projectile);
}
}

View File

@ -0,0 +1,92 @@
package su.nightexpress.excellentenchants.enchantment.impl.meta;
import org.bukkit.NamespacedKey;
import org.bukkit.Particle;
import org.bukkit.entity.Projectile;
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.PDCUtil;
import su.nightexpress.excellentenchants.ExcellentEnchantsAPI;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.enchantment.task.ArrowTrailsTask;
import java.util.Optional;
public final class ArrowImplementation implements Arrowed {
private final ExcellentEnchant enchant;
private final NamespacedKey projectileKey;
private final Particle trailParticle;
private final String trailData;
private ArrowImplementation(@NotNull ExcellentEnchant enchant,
@Nullable Particle trailParticle, @Nullable String trailData) {
this.enchant = enchant;
this.projectileKey = new NamespacedKey(ExcellentEnchantsAPI.PLUGIN, "arrow.enchant_id");
this.trailParticle = trailParticle;
this.trailData = trailData;
}
@NotNull
public static ArrowImplementation create(@NotNull ExcellentEnchant enchant) {
JYML cfg = enchant.getConfig();
Particle trailParticle = JOption.create("Settings.Arrow.Trail_Effect.Name", Particle.class, Particle.REDSTONE,
"Particle name for the arrow trail effect.",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Particle.html").read(cfg);
String trailData = JOption.create("Settings.Arrow.Trail_Effect.Data", "",
"Particle data for the particle effect.",
"This is required for certain particles only.").read(cfg);
return new ArrowImplementation(enchant, trailParticle, trailData);
}
@Override
@NotNull
public Arrowed getArrowImplementation() {
return this;
}
@Override
public void addTrail(@NotNull Projectile projectile) {
if (!this.enchant.hasVisualEffects()) return;
if (this.getTrailParticle().isEmpty()) return;
Particle particle = this.getTrailParticle().get();
String data = this.getTrailData().orElse("");
ArrowTrailsTask.add(projectile, particle, data);
}
@NotNull
@Override
public Optional<Particle> getTrailParticle() {
return trailParticle == null ? Optional.empty() : Optional.of(trailParticle);
}
@NotNull
@Override
public Optional<String> getTrailData() {
return trailData == null ? Optional.empty() : Optional.of(trailData);
}
@NotNull
public NamespacedKey getProjectileKey() {
return projectileKey;
}
@Override
public void addData(@NotNull Projectile projectile) {
PDCUtil.setData(projectile, this.getProjectileKey(), this.enchant.getId());
}
@Override
public boolean isOurProjectile(@NotNull Projectile projectile) {
String enchantId = PDCUtil.getStringData(projectile, this.getProjectileKey());
return this.enchant.getId().equalsIgnoreCase(enchantId);
}
}

View File

@ -0,0 +1,42 @@
package su.nightexpress.excellentenchants.enchantment.impl.meta;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
public final class ChanceImplementation implements Chanced {
public static final String PLACEHOLDER_CHANCE = "%enchantment_trigger_chance%";
//private final ExcellentEnchant enchant;
private final EnchantScaler triggerChance;
private ChanceImplementation(@NotNull ExcellentEnchant enchant, @NotNull EnchantScaler triggerChance) {
//this.enchant = enchant;
this.triggerChance = triggerChance;
}
@NotNull
public static ChanceImplementation create(@NotNull ExcellentEnchant enchant) {
return new ChanceImplementation(enchant, EnchantScaler.read(enchant, "Settings.Trigger_Chance", "100",
"A chance that this enchantment will be triggered."));
}
@Override
@NotNull
public Chanced getChanceImplementation() {
return this;
}
@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,86 @@
package su.nightexpress.excellentenchants.enchantment.impl.meta;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchantsAPI;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
public final class PotionImplementation implements Potioned {
public static final String PLACEHOLDER_POTION_LEVEL = "%enchantment_potion_level%";
public static final String PLACEHOLDER_POTION_DURATION = "%enchantment_potion_duration%";
public static final String PLACEHOLDER_POTION_TYPE = "%enchantment_potion_type%";
private final ExcellentEnchant enchant;
private final PotionEffectType effectType;
private final Scaler duration;
private final Scaler amplifier;
private final boolean isPermanent;
private PotionImplementation(@NotNull ExcellentEnchant enchant, @NotNull PotionEffectType effectType, boolean isPermanent) {
this.enchant = enchant;
this.effectType = effectType;
this.duration = EnchantScaler.read(enchant, "Settings.Potion_Effect.Duration", "5.0 * " + Placeholders.ENCHANTMENT_LEVEL,
"Potion effect duration (in seconds). This setting is useless for 'permanent' effects.");
this.amplifier = EnchantScaler.read(enchant, "Settings.Potion_Effect.Level", Placeholders.ENCHANTMENT_LEVEL,
"Potion effect level.");
this.isPermanent = isPermanent;
}
@Override
@NotNull
public Potioned getPotionImplementation() {
return this;
}
public static PotionImplementation create(@NotNull ExcellentEnchant enchant, @NotNull PotionEffectType type, boolean isPermanent) {
return new PotionImplementation(enchant, type, isPermanent);
}
@Override
public boolean isPermanent() {
return this.isPermanent;
}
@NotNull
public PotionEffectType getEffectType() {
return this.effectType;
}
public int getEffectDuration(int level) {
return (int) (this.duration.getValue(level) * 20);
}
public int getEffectAmplifier(int level) {
return (int) this.amplifier.getValue(level);
}
@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, false);
}
public boolean hasEffect(@NotNull LivingEntity entity) {
return EnchantManager.hasEnchantmentEffect(entity, this.enchant);
}
public boolean addEffect(@NotNull LivingEntity target, int level) {
if (this.isPermanent()) {
ExcellentEnchantsAPI.PLUGIN.getEnchantNMS().addEnchantmentEffect(target, this.enchant, this.createEffect(level));
}
else {
target.addPotionEffect(this.createEffect(level));
}
return true;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.block.Block;
import org.bukkit.enchantments.EnchantmentTarget;
@ -13,27 +13,24 @@ import org.bukkit.event.player.PlayerItemDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
import su.nightexpress.excellentenchants.hook.HookNCP;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.EnchantRegister;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.hook.impl.NoCheatPlusHook;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.EnchantRegister;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.List;
import java.util.function.UnaryOperator;
public class EnchantBlastMining extends IEnchantChanceTemplate implements BlockBreakEnchant {
private Scaler explosionPower;
private Scaler minBlockStrength;
public class EnchantBlastMining extends ExcellentEnchant implements Chanced, BlockBreakEnchant {
public static final String ID = "blast_mining";
public static final String PLACEHOLDER_EXPLOSION_POWER = "%enchantment_explosion_power%";
@ -41,15 +38,31 @@ public class EnchantBlastMining extends IEnchantChanceTemplate implements BlockB
private static final String META_EXPLOSION_SOURCE = ID + "_explosion_source";
private static final String META_EXPLOSION_MINED = ID + "_explosion_mined";
public EnchantBlastMining(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
private EnchantScaler explosionPower;
private EnchantScaler minBlockStrength;
private ChanceImplementation chanceImplementation;
public EnchantBlastMining(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.explosionPower = new EnchantScaler(this, "Settings.Explosion.Power");
this.minBlockStrength = new EnchantScaler(this, "Settings.Min_Block_Strength");
this.chanceImplementation = ChanceImplementation.create(this);
this.explosionPower = EnchantScaler.read(this, "Settings.Explosion.Power", "3.0 + (" + Placeholders.ENCHANTMENT_LEVEL + " - 1.0 * 0.25)",
"Explosion power. The more power = the more blocks (area) to explode.");
this.minBlockStrength = EnchantScaler.read(this, "Settings.Min_Block_Strength", "1.5 - " + Placeholders.ENCHANTMENT_LEVEL + " / 10",
"Minimal block strength value for the enchantment to have effect.",
"Block strength value is how long it takes to break the block by a hand.",
"For example, a Stone has 3.0 strength.");
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public double getExplosionPower(int level) {
@ -65,19 +78,11 @@ public class EnchantBlastMining extends IEnchantChanceTemplate implements BlockB
return (strength >= this.getMinBlockStrength(level));
}
@Override
protected void updateConfig() {
super.updateConfig();
cfg.addMissing("Settings.Min_Block_Strength", "1.5 - " + Placeholders.ENCHANTMENT_LEVEL + " / 10.0");
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
.replace(PLACEHOLDER_EXPLOSION_POWER, NumberUtil.format(this.getExplosionPower(level)))
);
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_EXPLOSION_POWER, NumberUtil.format(this.getExplosionPower(level)));
}
@Override
@ -93,8 +98,8 @@ public class EnchantBlastMining extends IEnchantChanceTemplate implements BlockB
}
@Override
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isEnchantmentAvailable(player)) return false;
public boolean onBreak(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(player)) return false;
if (EnchantRegister.VEINMINER != null && EnchantManager.hasEnchantment(item, EnchantRegister.VEINMINER)) return false;
if (EnchantRegister.TUNNEL != null && EnchantManager.hasEnchantment(item, EnchantRegister.TUNNEL)) return false;
@ -104,14 +109,13 @@ public class EnchantBlastMining extends IEnchantChanceTemplate implements BlockB
if (!this.isBlockHardEnough(block, level)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(player)) return false;
float power = (float) this.getExplosionPower(level);
player.setMetadata(META_EXPLOSION_SOURCE, new FixedMetadataValue(plugin, level));
HookNCP.exemptBlocks(player);
NoCheatPlusHook.exemptBlocks(player);
boolean exploded = block.getWorld().createExplosion(block.getLocation(), power, false, true, player);
HookNCP.unexemptBlocks(player);
NoCheatPlusHook.unexemptBlocks(player);
player.removeMetadata(META_EXPLOSION_SOURCE, plugin);
return exploded;
}
@ -140,7 +144,7 @@ public class EnchantBlastMining extends IEnchantChanceTemplate implements BlockB
blockList.clear();
}
// Do not damage around entities by en enchantment explosion.
// Do not damage around entities by enchantment explosion.
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlastExplosionDamage(EntityDamageByEntityEvent e) {
if (e.getCause() != DamageCause.ENTITY_EXPLOSION) return;

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Player;
@ -7,32 +7,36 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerItemDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantCurseOfBreaking extends IEnchantChanceTemplate {
private Scaler durabilityAmount;
public class EnchantCurseOfBreaking extends ExcellentEnchant implements Chanced {
public static final String ID = "curse_of_breaking";
public static final String PLACEHOLDER_DURABILITY_AMOUNT = "%enchantment_durability_amount%";
public EnchantCurseOfBreaking(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
private EnchantScaler durabilityAmount;
private ChanceImplementation chanceImplementation;
public EnchantCurseOfBreaking(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.durabilityAmount = new EnchantScaler(this, "Settings.Durability_Amount");
this.chanceImplementation = ChanceImplementation.create(this);
this.durabilityAmount = EnchantScaler.read(this, "Settings.Durability_Amount", Placeholders.ENCHANTMENT_LEVEL,
"Amount of durability points to be taken from the item.");
}
@Override
@ -40,6 +44,12 @@ public class EnchantCurseOfBreaking extends IEnchantChanceTemplate {
return true;
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public int getDurabilityAmount(int level) {
return (int) this.durabilityAmount.getValue(level);
}
@ -47,9 +57,8 @@ public class EnchantCurseOfBreaking extends IEnchantChanceTemplate {
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
.replace(PLACEHOLDER_DURABILITY_AMOUNT, NumberUtil.format(this.getDurabilityAmount(level)))
);
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_DURABILITY_AMOUNT, NumberUtil.format(this.getDurabilityAmount(level)));
}
@NotNull
@ -61,14 +70,13 @@ public class EnchantCurseOfBreaking extends IEnchantChanceTemplate {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onItemDurability(PlayerItemDamageEvent e) {
Player player = e.getPlayer();
if (!this.isEnchantmentAvailable(player)) return;
if (!this.isAvailableToUse(player)) return;
ItemStack item = e.getItem();
int level = EnchantManager.getItemEnchantLevel(item, this);
int level = EnchantManager.getEnchantmentLevel(item, this);
if (level < 1) return;
if (!this.checkTriggerChance(level)) return;
if (!this.takeCostItem(player)) return;
int durabilityAmount = this.getDurabilityAmount(level);
if (durabilityAmount <= 0) return;

View File

@ -0,0 +1,90 @@
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityDeathEvent;
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.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
public class EnchantCurseOfMisfortune extends ExcellentEnchant implements Chanced, BlockBreakEnchant, DeathEnchant {
public static final String ID = "curse_of_misfortune";
private boolean dropExp;
private ChanceImplementation chanceImplementation;
public EnchantCurseOfMisfortune(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.LOWEST);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
this.dropExp = JOption.create("Settings.Drop_Exp", false,
"When 'true' allows to drop exp from mobs/blocks.").read(cfg);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public boolean isDropExp() {
return dropExp;
}
@Override
@NotNull
public FitItemType[] getFitItemTypes() {
return new FitItemType[] {FitItemType.WEAPON, FitItemType.TOOL};
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BREAKABLE;
}
@Override
public boolean isCursed() {
return true;
}
@Override
public boolean onBreak(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(player)) return false;
if (!this.checkTriggerChance(level)) return false;
e.setDropItems(false);
if (!this.isDropExp()) e.setExpToDrop(0);
return true;
}
@Override
public boolean onKill(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, @NotNull Player killer, int level) {
if (!this.isAvailableToUse(killer)) return false;
if (!this.checkTriggerChance(level)) return false;
e.getDrops().clear();
if (!this.isDropExp()) e.setDroppedExp(0);
return true;
}
@Override
public boolean onDeath(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, int level) {
return false;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.Location;
import org.bukkit.Material;
@ -17,46 +17,45 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.LocationUtil;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantDropContainer;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CustomDropEnchant;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantDropContainer;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
public class EnchantDivineTouch extends IEnchantChanceTemplate implements BlockBreakEnchant, CustomDropEnchant {
public class EnchantDivineTouch extends ExcellentEnchant implements Chanced, BlockBreakEnchant, BlockDropEnchant {
public static final String ID = "divine_touch";
private static final String META_HANDLE = ID + "_handle";
private String particleName;
private String particleData;
private String spawnerName;
private ChanceImplementation chanceImplementation;
public EnchantDivineTouch(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
public EnchantDivineTouch(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.particleName = cfg.getString("Settings.Particle.Name", Particle.VILLAGER_HAPPY.name());
this.particleData = cfg.getString("Settings.Particle.Data", "");
this.spawnerName = StringUtil.color(cfg.getString("Settings.Spawner_Item.Name", "&aMob Spawner &7(%type%)"));
this.chanceImplementation = ChanceImplementation.create(this);
this.spawnerName = JOption.create("Settings.Spawner_Item.Name", "&aMob Spawner &7(" + Placeholders.GENERIC_TYPE + ")",
"Spawner item display name.",
"Placeholder '" + Placeholders.GENERIC_TYPE + "' for the mob type.").read(cfg);
}
@NotNull
@Override
protected void updateConfig() {
super.updateConfig();
cfg.remove("Settings.Particle_Effect");
cfg.addMissing("Settings.Particle.Name", Particle.VILLAGER_HAPPY.name());
cfg.addMissing("Settings.Particle.Data", "");
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@ -81,34 +80,35 @@ public class EnchantDivineTouch extends IEnchantChanceTemplate implements BlockB
spawnerItem.setSpawnedType(spawnerBlock.getSpawnedType());
spawnerItem.update(true);
stateItem.setBlockState(spawnerItem);
stateItem.setDisplayName(this.spawnerName.replace("%type%", plugin.getLangManager().getEnum(spawnerBlock.getSpawnedType())));
stateItem.setDisplayName(this.spawnerName.replace(Placeholders.GENERIC_TYPE, plugin.getLangManager().getEnum(spawnerBlock.getSpawnedType())));
itemSpawner.setItemMeta(stateItem);
return itemSpawner;
}
@Override
public void handleDrop(@NotNull EnchantDropContainer e, @NotNull Player player, @NotNull ItemStack item, int level) {
BlockDropItemEvent parent = e.getParent();
BlockState state = parent.getBlockState();
public boolean onDrop(@NotNull BlockDropItemEvent e, @NotNull EnchantDropContainer dropContainer, @NotNull Player player, @NotNull ItemStack item, int level) {
BlockState state = e.getBlockState();
Block block = state.getBlock();
if (!block.hasMetadata(META_HANDLE)) return;
if (!(state instanceof CreatureSpawner spawnerBlock)) return;
if (!block.hasMetadata(META_HANDLE)) return false;
if (!(state instanceof CreatureSpawner spawnerBlock)) return false;
e.getDrop().add(this.getSpawner(spawnerBlock));
dropContainer.getDrop().add(this.getSpawner(spawnerBlock));
Location location = LocationUtil.getCenter(block.getLocation());
EffectUtil.playEffect(location, this.particleName, this.particleData, 0.3f, 0.3f, 0.3f, 0.15f, 30);
if (this.hasVisualEffects()) {
EffectUtil.playEffect(location, Particle.VILLAGER_HAPPY, "", 0.3f, 0.3f, 0.3f, 0.15f, 30);
}
block.removeMetadata(META_HANDLE, this.plugin);
return true;
}
@Override
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
public boolean onBreak(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
Block block = e.getBlock();
if (!this.isEnchantmentAvailable(player)) return false;
if (!this.isAvailableToUse(player)) return false;
if (!(block.getState() instanceof CreatureSpawner spawnerBlock)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(player)) return false;
e.setExpToDrop(0);
e.setDropItems(true);

View File

@ -0,0 +1,33 @@
package su.nightexpress.excellentenchants.enchantment.impl.tool;
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.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
public class EnchantHaste extends PotionEnchant implements PassiveEnchant {
public static final String ID = "haste";
public EnchantHaste(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.FAST_DIGGING, true);
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.TOOL;
}
@Override
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(entity) || this.hasEffect(entity)) return false;
return this.addEffect(entity, level);
}
}

View File

@ -1,55 +1,59 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.function.UnaryOperator;
public class EnchantLuckyMiner extends IEnchantChanceTemplate implements BlockBreakEnchant {
private Scaler expModifier;
public class EnchantLuckyMiner extends ExcellentEnchant implements Chanced, BlockBreakEnchant {
public static final String ID = "lucky_miner";
private static final String PLACEHOLDER_EXP_MODIFIER = "%enchantment_exp_modifier%";
public EnchantLuckyMiner(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
private EnchantScaler expModifier;
private ChanceImplementation chanceImplementation;
public EnchantLuckyMiner(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.expModifier = new EnchantScaler(this, "Settings.Exp_Modifier");
this.chanceImplementation = ChanceImplementation.create(this);
this.expModifier = EnchantScaler.read(this, "Settings.Exp_Modifier", "1.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 0.5",
"Exp modifier value. The original exp amount will be multiplied on this value.");
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public double getExpModifier(int level) {
return this.expModifier.getValue(level);
}
@Override
protected void updateConfig() {
super.updateConfig();
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_EXP_MODIFIER, NumberUtil.format(this.getExpModifier(level) * 100D - 100D))
);
;
}
@Override
@ -65,11 +69,9 @@ public class EnchantLuckyMiner extends IEnchantChanceTemplate implements BlockBr
}
@Override
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (e.isCancelled()) return false;
if (!this.isEnchantmentAvailable(player)) return false;
public boolean onBreak(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(player)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(player)) return false;
double expMod = this.getExpModifier(level);
e.setExpToDrop((int) ((double) e.getExpToDrop() * expMod));

View File

@ -1,6 +1,5 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import com.google.common.collect.Sets;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
@ -15,37 +14,40 @@ import org.bukkit.event.player.PlayerInteractEvent;
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.config.JOption;
import su.nexmedia.engine.utils.MessageUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.InteractEnchant;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.Set;
public class EnchantReplanter extends IEnchantChanceTemplate implements InteractEnchant, BlockBreakEnchant {
public class EnchantReplanter extends ExcellentEnchant implements InteractEnchant, BlockBreakEnchant {
public static final String ID = "replanter";
private boolean replantOnRightClick;
private boolean replantOnPlantBreak;
public static final String ID = "replanter";
private static final Set<Material> CROPS = Sets.newHashSet(
Material.WHEAT_SEEDS, Material.BEETROOT_SEEDS, Material.MELON_SEEDS, Material.PUMPKIN_SEEDS,
private static final Set<Material> CROPS = Set.of(
Material.WHEAT_SEEDS, Material.BEETROOT_SEEDS,
Material.MELON_SEEDS, Material.PUMPKIN_SEEDS,
Material.POTATO, Material.CARROT, Material.NETHER_WART);
public EnchantReplanter(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.HIGH);
public EnchantReplanter(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.HIGH);
}
@Override
public void loadConfig() {
super.loadConfig();
this.replantOnRightClick = cfg.getBoolean("Settings.Replant.On_Right_Click");
this.replantOnPlantBreak = cfg.getBoolean("Settings.Replant.On_Plant_Break");
this.replantOnRightClick = JOption.create("Settings.Replant.On_Right_Click", true,
"When 'true', player will be able to replant crops when right-clicking farmland blocks.").read(cfg);
this.replantOnPlantBreak = JOption.create("Settings.Replant.On_Plant_Break", true,
"When 'true', crops will be automatically replanted when player break plants with enchanted tool in hand.").read(cfg);
}
public boolean isReplantOnPlantBreak() {
@ -91,11 +93,6 @@ public class EnchantReplanter extends IEnchantChanceTemplate implements Interact
return true;
}
@Override
protected void updateConfig() {
super.updateConfig();
}
@Override
@NotNull
public FitItemType[] getFitItemTypes() {
@ -109,8 +106,8 @@ public class EnchantReplanter extends IEnchantChanceTemplate implements Interact
}
@Override
public boolean use(@NotNull PlayerInteractEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isEnchantmentAvailable(player)) return false;
public boolean onInteract(@NotNull PlayerInteractEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(player)) return false;
if (!this.isReplantOnRightClick()) return false;
// Check for a event hand. We dont want to trigger it twice.
@ -126,9 +123,6 @@ public class EnchantReplanter extends IEnchantChanceTemplate implements Interact
if (blockGround == null) return false;
if (blockGround.getType() != Material.FARMLAND && blockGround.getType() != Material.SOUL_SAND) return false;
// Check enchantment trigger chance.
if (!this.checkTriggerChance(level)) return false;
// Check if someting is already growing on the farmland.
Block blockPlant = blockGround.getRelative(BlockFace.UP);
if (!blockPlant.isEmpty()) return false;
@ -149,8 +143,8 @@ public class EnchantReplanter extends IEnchantChanceTemplate implements Interact
}
@Override
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isEnchantmentAvailable(player)) return false;
public boolean onBreak(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(player)) return false;
if (!this.isReplantOnPlantBreak()) return false;
Block blockPlant = e.getBlock();
@ -164,9 +158,6 @@ public class EnchantReplanter extends IEnchantChanceTemplate implements Interact
BlockData dataPlant = blockPlant.getBlockData();
if (!(dataPlant instanceof Ageable plant)) return false;
// Check enchantment trigger chance.
if (!this.checkTriggerChance(level)) return false;
// Check if crop is not at its maximal age to prevent accidient replant.
/*if (plant.getAge() < plant.getMaximumAge()) {
e.setCancelled(true);

View File

@ -1,6 +1,5 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
@ -18,48 +17,45 @@ import org.bukkit.event.inventory.InventoryPickupItemEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.ItemUtil;
import su.nexmedia.engine.utils.PDCUtil;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantDropContainer;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.type.CustomDropEnchant;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantDropContainer;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.Map;
import java.util.TreeMap;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class EnchantSilkChest extends IEnchantChanceTemplate implements CustomDropEnchant {
private final Map<Integer, NamespacedKey> keyItems;
private String chestName;
public class EnchantSilkChest extends ExcellentEnchant implements BlockDropEnchant {
public static final String ID = "silk_chest";
public EnchantSilkChest(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.HIGH);
this.keyItems = new TreeMap<>();
private String chestName;
private List<String> chestLore;
private final NamespacedKey keyChest;
for (int pos = 0; pos < 27; pos++) {
this.getItemKey(pos);
}
public EnchantSilkChest(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.HIGH);
this.keyChest = new NamespacedKey(plugin, ID + ".item");
}
@Override
public void loadConfig() {
super.loadConfig();
this.chestName = StringUtil.color(cfg.getString("Settings.Chest_Item.Name", "%name% &7(%items% items)"));
}
@Override
protected void updateConfig() {
super.updateConfig();
this.chestName = JOption.create("Settings.Chest_Item.Name", "Chest &7(" + Placeholders.GENERIC_AMOUNT + " items)",
"Chest item display name.",
"Use '" + Placeholders.GENERIC_AMOUNT + "' for items amount.").read(cfg);
this.chestLore = JOption.create("Settings.Chest_Item.Lore", new ArrayList<>(),
"Chest item lore.",
"Use '" + Placeholders.GENERIC_AMOUNT + "' for items amount.").read(cfg);
}
@Override
@ -74,20 +70,34 @@ public class EnchantSilkChest extends IEnchantChanceTemplate implements CustomDr
return EnchantmentTarget.TOOL;
}
private NamespacedKey getItemKey(int pos) {
return this.keyItems.computeIfAbsent(pos, key -> new NamespacedKey(plugin, "silkchest_item_" + pos));
}
public boolean isSilkChest(@NotNull ItemStack item) {
return PDCUtil.getStringData(item, this.getItemKey(0)) != null;
return PDCUtil.getBooleanData(item, this.keyChest);
}
@NotNull
public ItemStack getSilkChest(@NotNull Chest chest) {
ItemStack chestItem = new ItemStack(chest.getType());
ItemStack chestStack = new ItemStack(chest.getType());
BlockStateMeta stateMeta = (BlockStateMeta) chestStack.getItemMeta();
if (stateMeta == null) return chestStack;
Chest chestItem = (Chest) stateMeta.getBlockState();
chestItem.getBlockInventory().setContents(chest.getBlockInventory().getContents());
chestItem.update(true);
int amount = (int) Stream.of(chestItem.getBlockInventory().getContents()).filter(i -> i != null && !i.getType().isAir()).count();
stateMeta.setBlockState(chestItem);
stateMeta.setDisplayName(this.chestName);
stateMeta.setLore(this.chestLore);
chestStack.setItemMeta(stateMeta);
ItemUtil.replace(chestStack, str -> str.replace(Placeholders.GENERIC_AMOUNT, String.valueOf(amount)));
PDCUtil.setData(chestStack, this.keyChest, true);
return chestStack;
// Store and count chest items.
int amount = 0;
/*int amount = 0;
int count = 0;
for (ItemStack itemInv : chest.getBlockInventory().getContents()) {
if (itemInv == null) itemInv = new ItemStack(Material.AIR);
@ -111,30 +121,29 @@ public class EnchantSilkChest extends IEnchantChanceTemplate implements CustomDr
chestItem.setItemMeta(meta);
}
return chestItem;
return chestItem;*/
}
@Override
public void handleDrop(@NotNull EnchantDropContainer e, @NotNull Player player, @NotNull ItemStack item, int level) {
BlockDropItemEvent parent = e.getParent();
BlockState state = parent.getBlockState();
public boolean onDrop(@NotNull BlockDropItemEvent e, @NotNull EnchantDropContainer dropContainer, @NotNull Player player, @NotNull ItemStack item, int level) {
BlockState state = e.getBlockState();
Block block = state.getBlock();
if (!this.isEnchantmentAvailable(player)) return;
if (!(state instanceof Chest chest)) return;
if (!this.checkTriggerChance(level)) return;
if (!this.takeCostItem(player)) return;
if (!this.isAvailableToUse(player)) return false;
if (!(state instanceof Chest chest)) return false;
// Добавляем в сундук обратно предметы из дроп листа, кроме самого сундука.
parent.getItems().removeIf(drop -> drop.getItemStack().getType() == state.getType() && drop.getItemStack().getAmount() == 1);
chest.getBlockInventory().addItem(parent.getItems().stream().map(Item::getItemStack).toList().toArray(new ItemStack[0]));
e.getItems().removeIf(drop -> drop.getItemStack().getType() == state.getType() && drop.getItemStack().getAmount() == 1);
chest.getBlockInventory().addItem(e.getItems().stream().map(Item::getItemStack).toList().toArray(new ItemStack[0]));
// Добавляем кастомный сундук в кастомный дроп лист.
e.getDrop().add(this.getSilkChest(chest));
dropContainer.getDrop().add(this.getSilkChest(chest));
// Очищаем инвентарь сундука и дефолтный дроп лист.
chest.getBlockInventory().clear();
parent.getItems().clear();
e.getItems().clear();
return true;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -149,14 +158,14 @@ public class EnchantSilkChest extends IEnchantChanceTemplate implements CustomDr
chest.setCustomName(null);
chest.update(true);
Inventory inventory = chest.getBlockInventory();
for (int pos = 0; pos < inventory.getSize(); pos++) {
//Inventory inventory = chest.getBlockInventory();
/*for (int pos = 0; pos < inventory.getSize(); pos++) {
String data = PDCUtil.getStringData(item, this.getItemKey(pos));
if (data == null) continue;
ItemStack itemInv = ItemUtil.fromBase64(data);
inventory.setItem(pos, itemInv);
}
}*/
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.Location;
import org.bukkit.Material;
@ -11,38 +11,43 @@ import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.LocationUtil;
import su.nexmedia.engine.utils.MessageUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantDropContainer;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.HashMap;
import java.util.Map;
public class EnchantSmelter extends IEnchantChanceTemplate implements BlockDropEnchant {
public class EnchantSmelter extends ExcellentEnchant implements Chanced, BlockDropEnchant {
public static final String ID = "smelter";
private Sound sound;
private String particleName;
private String particleData;
private Map<Material, Material> smeltingTable;
private ChanceImplementation chanceImplementation;
public EnchantSmelter(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
public EnchantSmelter(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.sound = cfg.getEnum("Settings.Sound", Sound.class);
this.particleName = cfg.getString("Settings.Particle.Name", Particle.FLAME.name());
this.particleData = cfg.getString("Settings.Particle.Data", "");
this.chanceImplementation = ChanceImplementation.create(this);
this.sound = JOption.create("Settings.Sound", Sound.class, Sound.BLOCK_LAVA_EXTINGUISH,
"Sound to play on smelting.",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html").read(cfg);
this.smeltingTable = new HashMap<>();
for (String sFrom : cfg.getSection("Settings.Smelting_Table")) {
Material mFrom = Material.getMaterial(sFrom.toUpperCase());
@ -58,16 +63,17 @@ public class EnchantSmelter extends IEnchantChanceTemplate implements BlockDropE
}
this.smeltingTable.put(mFrom, mTo);
}
this.cfg.setComments("Settings.Smelting_Table",
"Table of Original -> Smelted items.",
"Syntax: 'Material Source : Material Result'.",
"Note: Material source is material name of the dropped item, not the broken block!",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html");
}
@NotNull
@Override
protected void updateConfig() {
super.updateConfig();
cfg.remove("Settings.Particle_Effect");
cfg.addMissing("Settings.Sound", Sound.BLOCK_LAVA_EXTINGUISH.name());
cfg.addMissing("Settings.Particle.Name", Particle.FLAME.name());
cfg.addMissing("Settings.Particle.Data", "");
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@ -76,13 +82,6 @@ public class EnchantSmelter extends IEnchantChanceTemplate implements BlockDropE
return new FitItemType[]{FitItemType.PICKAXE, FitItemType.AXE, FitItemType.SHOVEL};
}
/*@Override
protected void addConflicts() {
super.addConflicts();
this.addConflict(Enchantment.SILK_TOUCH);
this.addConflict(EnchantRegister.DIVINE_TOUCH);
}*/
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
@ -90,12 +89,11 @@ public class EnchantSmelter extends IEnchantChanceTemplate implements BlockDropE
}
@Override
public boolean use(@NotNull BlockDropItemEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
public boolean onDrop(@NotNull BlockDropItemEvent e, @NotNull EnchantDropContainer dropContainer, @NotNull Player player, @NotNull ItemStack item, int level) {
if (e.getBlockState() instanceof Container) return false;
if (!this.isEnchantmentAvailable(player)) return false;
if (!this.isAvailableToUse(player)) return false;
if (!this.checkTriggerChance(level)) return false;
if (e.getItems().stream().noneMatch(drop -> this.isSmeltable(drop.getItemStack().getType()))) return false;
if (!this.takeCostItem(player)) return false;
e.getItems().forEach(drop -> {
Material material = this.smeltingTable.get(drop.getItemStack().getType());
@ -103,17 +101,15 @@ public class EnchantSmelter extends IEnchantChanceTemplate implements BlockDropE
});
Block block = e.getBlockState().getBlock();
this.playEffect(block);
if (this.hasVisualEffects()) {
Location location = LocationUtil.getCenter(block.getLocation(), true);
MessageUtil.sound(location, this.sound);
EffectUtil.playEffect(location, Particle.FLAME, "", 0.2f, 0.2f, 0.2f, 0.05f, 30);
}
return true;
}
public boolean isSmeltable(@NotNull Material material) {
return this.smeltingTable.containsKey(material);
}
public void playEffect(@NotNull Block block) {
Location location = LocationUtil.getCenter(block.getLocation(), true);
MessageUtil.sound(location, this.sound);
EffectUtil.playEffect(location, this.particleName, this.particleData, 0.2f, 0.2f, 0.2f, 0.05f, 30);
}
}

View File

@ -0,0 +1,56 @@
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.PlayerUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantDropContainer;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class EnchantTelekinesis extends ExcellentEnchant implements BlockDropEnchant {
public static final String ID = "telekinesis";
public EnchantTelekinesis(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.LOWEST);
}
@Override
@NotNull
public FitItemType[] getFitItemTypes() {
return new FitItemType[]{FitItemType.TOOL};
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.TOOL;
}
@Override
public boolean onDrop(@NotNull BlockDropItemEvent e, @NotNull EnchantDropContainer dropContainer, @NotNull Player player, @NotNull ItemStack item, int level) {
if (!this.isAvailableToUse(player)) return false;
List<ItemStack> drops = new ArrayList<>();
drops.addAll(e.getItems().stream().map(Item::getItemStack).toList());
drops.addAll(dropContainer.getDrop());
drops.removeIf(Objects::isNull);
drops.forEach(drop -> PlayerUtil.addItem(player, drop));
dropContainer.getDrop().clear();
e.getItems().clear();
return true;
}
}

View File

@ -0,0 +1,121 @@
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.manager.ICleanable;
import su.nexmedia.engine.utils.random.Rnd;
import su.nexmedia.playerblocktracker.PlayerBlockTracker;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantDropContainer;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.*;
import java.util.function.Predicate;
public class EnchantTreasures extends ExcellentEnchant implements Chanced, BlockDropEnchant, ICleanable {
public static final String ID = "treasures";
private Map<Material, Map<Material, Double>> treasures;
private ChanceImplementation chanceImplementation;
private final Predicate<Block> blockTracker;
public EnchantTreasures(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
PlayerBlockTracker.initialize(plugin);
PlayerBlockTracker.BLOCK_FILTERS.add(this.blockTracker = (block) -> {
return !this.getTreasures(block.getType()).isEmpty();
});
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
this.treasures = new HashMap<>();
for (String sFromArray : cfg.getSection("Settings.Treasures")) {
for (String sFrom : sFromArray.split(",")) {
Material mFrom = Material.getMaterial(sFrom.toUpperCase());
if (mFrom == null) {
plugin.error("[Treasures] Invalid source material '" + sFrom + "' !");
continue;
}
Map<Material, Double> treasuresList = new HashMap<>();
for (String sTo : cfg.getSection("Settings.Treasures." + sFromArray)) {
Material mTo = Material.getMaterial(sTo.toUpperCase());
if (mTo == null) {
plugin.error("[Treasures] Invalid result material '" + sTo + "' for '" + sFromArray + "' !");
continue;
}
double tChance = cfg.getDouble("Settings.Treasures." + sFromArray + "." + sTo);
treasuresList.put(mTo, tChance);
}
this.treasures.put(mFrom, treasuresList);
}
}
this.cfg.setComments("Settings.Treasures",
"List of source materials (blocks that will drop additional loot). Separated by a comma.",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html");
}
@Override
public void clear() {
PlayerBlockTracker.BLOCK_FILTERS.remove(this.blockTracker);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@NotNull
public FitItemType[] getFitItemTypes() {
return new FitItemType[]{FitItemType.PICKAXE, FitItemType.AXE, FitItemType.SHOVEL};
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.TOOL;
}
@Override
public boolean onDrop(@NotNull BlockDropItemEvent e, @NotNull EnchantDropContainer dropContainer, @NotNull Player player, @NotNull ItemStack item, int level) {
Block block = e.getBlockState().getBlock();
if (!this.isAvailableToUse(player)) return false;
if (PlayerBlockTracker.isTracked(block)) return false;
if (!this.checkTriggerChance(level)) return false;
dropContainer.getDrop().addAll(this.getTreasures(e.getBlockState().getType()));
return true;
}
@NotNull
public final List<ItemStack> getTreasures(@NotNull Material type) {
List<ItemStack> list = new ArrayList<>();
Map<Material, Double> treasures = this.treasures.getOrDefault(type, Collections.emptyMap());
treasures.forEach((mat, chance) -> {
if (mat.isAir() || !mat.isItem() || !Rnd.chance(chance)) return;
list.add(new ItemStack(mat));
});
return list;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.Material;
import org.bukkit.Particle;
@ -10,24 +10,22 @@ import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.LocationUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
import su.nightexpress.excellentenchants.hook.HookNCP;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.EnchantRegister;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.hook.impl.NoCheatPlusHook;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.EnchantRegister;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.HashSet;
import java.util.Set;
public class EnchantTunnel extends IEnchantChanceTemplate implements BlockBreakEnchant {
private boolean disableOnSneak;
public class EnchantTunnel extends ExcellentEnchant implements BlockBreakEnchant {
public static final String ID = "tunnel";
private static final String META_BLOCK_TUNNEL = ID + "_block_tunneled";
@ -40,19 +38,17 @@ public class EnchantTunnel extends IEnchantChanceTemplate implements BlockBreakE
INTERACTABLE_BLOCKS.add(Material.DEEPSLATE_REDSTONE_ORE);
}
public EnchantTunnel(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.HIGH);
private boolean disableOnSneak;
public EnchantTunnel(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.HIGH);
}
@Override
public void loadConfig() {
super.loadConfig();
this.disableOnSneak = cfg.getBoolean("Settings.Ignore_When_Sneaking");
}
@Override
protected void updateConfig() {
super.updateConfig();
this.disableOnSneak = JOption.create("Settings.Ignore_When_Sneaking", true,
"When 'true' the enchantment won't be triggered when sneaking.").read(cfg);
}
@Override
@ -68,17 +64,15 @@ public class EnchantTunnel extends IEnchantChanceTemplate implements BlockBreakE
}
@Override
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
public boolean onBreak(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
Block block = e.getBlock();
if (!this.isEnchantmentAvailable(player)) return false;
if (!this.isAvailableToUse(player)) return false;
if (this.disableOnSneak && player.isSneaking()) return false;
if (EnchantRegister.VEINMINER != null && EnchantManager.hasEnchantment(item, EnchantRegister.VEINMINER)) return false;
if (EnchantRegister.BLAST_MINING != null && EnchantManager.hasEnchantment(item, EnchantRegister.BLAST_MINING)) return false;
if (block.hasMetadata(META_BLOCK_TUNNEL)) return false;
if (block.getType().isInteractable() && !INTERACTABLE_BLOCKS.contains(block.getType())) return false;
if (block.getDrops(item).isEmpty()) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(player)) return false;
BlockFace dir = LocationUtil.getDirection(player);
boolean isY = dir != null && block.getRelative(dir.getOppositeFace()).isEmpty();
@ -90,7 +84,7 @@ public class EnchantTunnel extends IEnchantChanceTemplate implements BlockBreakE
else if (level == 2) blocksBroken = 5;
else if (level == 3) blocksBroken = 9;
HookNCP.exemptBlocks(player);
NoCheatPlusHook.exemptBlocks(player);
for (int i = 0; i < blocksBroken; i++) {
if (item.getType().isAir()) break;
@ -127,7 +121,7 @@ public class EnchantTunnel extends IEnchantChanceTemplate implements BlockBreakE
blockAdd.removeMetadata(META_BLOCK_TUNNEL, plugin);
}
HookNCP.unexemptBlocks(player);
NoCheatPlusHook.unexemptBlocks(player);
return true;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.tool;
package su.nightexpress.excellentenchants.enchantment.impl.tool;
import org.bukkit.Material;
import org.bukkit.Particle;
@ -10,19 +10,20 @@ import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.LocationUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
import su.nightexpress.excellentenchants.hook.HookNCP;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.EnchantRegister;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.manager.type.FitItemType;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.hook.impl.NoCheatPlusHook;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.EnchantRegister;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import su.nightexpress.excellentenchants.enchantment.type.FitItemType;
import java.util.HashSet;
import java.util.Objects;
@ -31,26 +32,31 @@ import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class EnchantVeinminer extends IEnchantChanceTemplate implements BlockBreakEnchant {
public class EnchantVeinminer extends ExcellentEnchant implements BlockBreakEnchant {
public static final String ID = "veinminer";
private static final BlockFace[] AREA = {BlockFace.UP, BlockFace.DOWN, BlockFace.EAST, BlockFace.WEST, BlockFace.SOUTH, BlockFace.NORTH};
private static final String META_BLOCK_VEINED = ID + "_block_veined";
private static final String PLACEHOLDER_BLOCK_LIMIT = "%enchantment_block_limit%";
private Scaler blocksLimit;
private Set<Material> blocksAffected;
public static final String ID = "veinminer";
private static final BlockFace[] AREA = {BlockFace.UP, BlockFace.DOWN, BlockFace.EAST, BlockFace.WEST, BlockFace.SOUTH, BlockFace.NORTH};
private static final String META_BLOCK_VEINED = ID + "_block_veined";
private static final String PLACEHOLDER_BLOCK_LIMIT = "%enchantment_block_limit%";
public EnchantVeinminer(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.HIGH);
public EnchantVeinminer(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.HIGH);
}
@Override
public void loadConfig() {
super.loadConfig();
this.blocksLimit = new EnchantScaler(this, "Settings.Blocks.Max_At_Once");
this.blocksAffected = cfg.getStringSet("Settings.Blocks.Affected").stream()
this.blocksLimit = EnchantScaler.read(this, "Settings.Blocks.Max_At_Once", "6 + " + Placeholders.ENCHANTMENT_LEVEL,
"How much amount of blocks can be destroted at single use?");
this.blocksAffected = JOption.create("Settings.Blocks.Affected", new HashSet<>(),
"List of blocks, that will be affected by this enchantment.",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html").read(cfg).stream()
.map(type -> Material.getMaterial(type.toUpperCase())).filter(Objects::nonNull).collect(Collectors.toSet());
}
@ -66,9 +72,9 @@ public class EnchantVeinminer extends IEnchantChanceTemplate implements BlockBre
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_BLOCK_LIMIT, String.valueOf(this.getBlocksLimit(level)))
);
;
}
@Override
@ -114,22 +120,19 @@ public class EnchantVeinminer extends IEnchantChanceTemplate implements BlockBre
}
@Override
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack tool, int level) {
if (!this.isEnchantmentAvailable(player)) return false;
public boolean onBreak(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack tool, int level) {
if (!this.isAvailableToUse(player)) return false;
if (EnchantRegister.TUNNEL != null && EnchantManager.hasEnchantment(tool, EnchantRegister.TUNNEL)) return false;
if (EnchantRegister.BLAST_MINING != null && EnchantManager.hasEnchantment(tool, EnchantRegister.BLAST_MINING)) return false;
Block block = e.getBlock();
if (block.hasMetadata(META_BLOCK_VEINED)) return false;
if (block.getDrops(tool).isEmpty()) return false;
if (!this.getBlocksAffected().contains(block.getType())) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(player)) return false;
HookNCP.exemptBlocks(player);
NoCheatPlusHook.exemptBlocks(player);
this.vein(player, block, level);
HookNCP.unexemptBlocks(player);
NoCheatPlusHook.unexemptBlocks(player);
return true;
}

View File

@ -0,0 +1,77 @@
package su.nightexpress.excellentenchants.enchantment.impl.universal;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.AnvilInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
public class EnchantCurseOfFragility extends ExcellentEnchant {
public static final String ID = "curse_of_fragility";
public EnchantCurseOfFragility(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.BREAKABLE;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onItemAnvil(PrepareAnvilEvent e) {
AnvilInventory inventory = e.getInventory();
ItemStack first = inventory.getItem(0);
ItemStack second = inventory.getItem(1);
boolean cursedFirst = (first != null && EnchantManager.getEnchantmentLevel(first, this) >= 1);
boolean cursedSecond = (second != null && EnchantManager.getEnchantmentLevel(second, this) >= 1);
if (cursedFirst || cursedSecond) {
e.setResult(null);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemGrindstoneClick(InventoryClickEvent e) {
Inventory inventory = e.getInventory();
if (inventory.getType() != InventoryType.GRINDSTONE) return;
this.stopGrindstone(inventory);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemGrindstoneDrag(InventoryDragEvent e) {
Inventory inventory = e.getInventory();
if (inventory.getType() != InventoryType.GRINDSTONE) return;
this.stopGrindstone(inventory);
}
private void stopGrindstone(@NotNull Inventory inventory) {
plugin.getScheduler().runTask(plugin, () -> {
ItemStack first = inventory.getItem(0);
ItemStack second = inventory.getItem(1);
boolean cursedFirst = (first != null && EnchantManager.getEnchantmentLevel(first, this) >= 1);
boolean cursedSecond = (second != null && EnchantManager.getEnchantmentLevel(second, this) >= 1);
if (cursedFirst || cursedSecond) {
inventory.setItem(2, null);
}
});
}
}

View File

@ -0,0 +1,87 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.Set;
import java.util.function.UnaryOperator;
public class EnchantBaneOfNetherspawn extends ExcellentEnchant implements CombatEnchant {
public static final String ID = "bane_of_netherspawn";
private static final String PLACEHOLDER_DAMAGE = "%enchantment_damage%";
private static final Set<EntityType> ENTITY_TYPES = Set.of(
EntityType.BLAZE, EntityType.MAGMA_CUBE,
EntityType.WITHER_SKELETON, EntityType.GHAST, EntityType.WITHER,
EntityType.PIGLIN, EntityType.PIGLIN_BRUTE,
EntityType.ZOGLIN, EntityType.HOGLIN,
EntityType.STRIDER, EntityType.ZOMBIFIED_PIGLIN
);
private boolean damageModifier;
private EnchantScaler damageFormula;
public EnchantBaneOfNetherspawn(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.damageModifier = JOption.create("Settings.Damage.As_Modifier", false,
"When 'true' multiplies the damage. When 'false' sums plain values.").read(cfg);
this.damageFormula = EnchantScaler.read(this, "Settings.Damage.Amount", "0.5 * " + Placeholders.ENCHANTMENT_LEVEL,
"Amount of additional damage.");
}
public double getDamageModifier(int level) {
return this.damageFormula.getValue(level);
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_DAMAGE, NumberUtil.format(this.getDamageModifier(level)));
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!ENTITY_TYPES.contains(victim.getType())) return false;
if (!this.isAvailableToUse(damager)) return false;
double damageEvent = e.getDamage();
double damageAdd = this.getDamageModifier(level);
e.setDamage(this.damageModifier ? damageEvent * damageAdd : damageEvent + damageAdd);
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.SMOKE_NORMAL, "", 0.25, 0.25, 0.25, 0.1f, 30);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,62 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantBlindness extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "blindness";
private ChanceImplementation chanceImplementation;
public EnchantBlindness(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.BLINDNESS, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.addEffect(victim, level)) return false;
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.SMOKE_NORMAL, "", 0.25, 0.25, 0.25, 0.1f, 30);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,63 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantConfusion extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "confusion";
private ChanceImplementation chanceImplementation;
public EnchantConfusion(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.CONFUSION, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.addEffect(victim, level)) return false;
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.ITEM_CRACK, Material.ROTTEN_FLESH.name(), 0.25, 0.25, 0.25, 0.1f, 30);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,78 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import com.google.common.collect.Sets;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.*;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import java.util.Set;
public class EnchantCure extends ExcellentEnchant implements Chanced, CombatEnchant {
public static final String ID = "cure";
private ChanceImplementation chanceImplementation;
private static final Set<EntityType> CUREABLE = Sets.newHashSet(EntityType.ZOMBIFIED_PIGLIN, EntityType.ZOMBIE_VILLAGER);
public EnchantCure(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!CUREABLE.contains(victim.getType())) return false;
if (!this.checkTriggerChance(level)) return false;
if (!(damager instanceof Player player)) return false;
e.setCancelled(true);
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.CLOUD, "", 0.25, 0.25, 0.25, 0.1f, 30);
}
if (victim instanceof PigZombie pigZombie) {
victim.getWorld().spawn(victim.getLocation(), Piglin.class);
victim.remove();
}
else if (victim instanceof ZombieVillager zombieVillager) {
zombieVillager.setConversionTime(1);
zombieVillager.setConversionPlayer(player);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.weapon;
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.Sound;
@ -11,57 +11,56 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.MessageUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantCutter extends IEnchantChanceTemplate implements CombatEnchant {
protected Scaler durabilityReduction;
protected Sound sound;
public class EnchantCutter extends ExcellentEnchant implements Chanced, CombatEnchant {
public static final String ID = "cutter";
private static final String PLACEHOLDER_DURABILITY_DAMAGE = "%enchantment_durability_damage%";
public EnchantCutter(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.LOWEST);
private EnchantScaler durabilityReduction;
private ChanceImplementation chanceImplementation;
public EnchantCutter(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.LOWEST);
}
@Override
public void loadConfig() {
super.loadConfig();
this.durabilityReduction = new EnchantScaler(this, "Settings.Item.Durability_Reduction");
this.sound = cfg.getEnum("Settings.Item.Sound", Sound.class);
this.chanceImplementation = ChanceImplementation.create(this);
this.durabilityReduction = EnchantScaler.read(this, "Settings.Item.Durability_Reduction", Placeholders.ENCHANTMENT_LEVEL + " / 100",
"Amount (in percent) of how much item durability will be reduced.");
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public final double getDurabilityReduction(int level) {
return this.durabilityReduction.getValue(level);
}
@Override
protected void updateConfig() {
super.updateConfig();
cfg.addMissing("Settings.Item.Sound", Sound.ENTITY_ITEM_BREAK.name());
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
.replace(PLACEHOLDER_DURABILITY_DAMAGE, NumberUtil.format(this.getDurabilityReduction(level) * 100D))
);
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_DURABILITY_DAMAGE, NumberUtil.format(this.getDurabilityReduction(level) * 100D));
}
@Override
@ -71,8 +70,8 @@ public class EnchantCutter extends IEnchantChanceTemplate implements CombatEncha
}
@Override
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isEnchantmentAvailable(damager)) return false;
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
EntityEquipment equipment = victim.getEquipment();
if (equipment == null) return false;
@ -88,7 +87,6 @@ public class EnchantCutter extends IEnchantChanceTemplate implements CombatEncha
ItemMeta meta = itemCut.getItemMeta();
if (!(meta instanceof Damageable damageable)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(damager)) return false;
damageable.setDamage((int) (itemCut.getType().getMaxDurability() * this.getDurabilityReduction(level)));
itemCut.setItemMeta(damageable);
@ -100,8 +98,15 @@ public class EnchantCutter extends IEnchantChanceTemplate implements CombatEncha
drop.setPickupDelay(50);
drop.getVelocity().multiply(3D);
EffectUtil.playEffect(victim.getEyeLocation(), Particle.ITEM_CRACK.name(), itemCut.getType().name(), 0.2f, 0.15f, 0.2f, 0.15f, 40);
MessageUtil.sound(victim.getLocation(), this.sound);
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.ITEM_CRACK.name(), itemCut.getType().name(), 0.2f, 0.15f, 0.2f, 0.15f, 40);
MessageUtil.sound(victim.getLocation(), Sound.ENTITY_ITEM_BREAK);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,143 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.ItemUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class EnchantDecapitator extends ExcellentEnchant implements Chanced, DeathEnchant {
public static final String ID = "decapitator";
private Set<String> ignoredEntityTypes;
private String headName;
private Map<String, String> headTextures;
private ChanceImplementation chanceImplementation;
public EnchantDecapitator(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
this.ignoredEntityTypes = JOption.create("Settings.Ignored_Entity_Types", new HashSet<>(),
"List of entities, that won't drop heads.").read(cfg).stream().map(String::toUpperCase).collect(Collectors.toSet());
this.headName = JOption.create("Settings.Head_Item.Name", "&c" + Placeholders.GENERIC_TYPE + "'s Head",
"Head item display name. Use '" + Placeholders.GENERIC_TYPE + "' for entity name.").read(cfg);
this.headTextures = new HashMap<>();
for (String sType : cfg.getSection("Settings.Head_Item.Textures")) {
this.headTextures.put(sType.toUpperCase(), cfg.getString("Settings.Head_Item.Textures." + sType, ""));
}
this.cfg.setComments("Settings.Head_Item.Textures",
"Head texture values for each entity type.",
"You can take some from http://minecraft-heads.com",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html");
/*this.headTextures = new JOption<Map<String, String>>("Settings.Head_Item.Textures",
(cfg, path, def) -> cfg.getSection(path).stream().collect(Collectors.toMap(String::toUpperCase, v -> cfg.getString(path + "." + v, ""))),
HashMap::new,
"Head texture values for each entity type.",
"You can take some from http://minecraft-heads.com",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html").read(cfg);*/
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onDeath(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, int level) {
return false;
}
@Override
public boolean onKill(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, @NotNull Player killer, int level) {
if (!this.isAvailableToUse(entity)) return false;
EntityType entityType = entity.getType();
if (this.ignoredEntityTypes.contains(entityType.name())) return false;
if (!this.checkTriggerChance(level)) return false;
ItemStack item;
if (entityType == EntityType.WITHER_SKELETON || entityType == EntityType.WITHER) {
item = new ItemStack(Material.WITHER_SKELETON_SKULL);
}
else if (entityType == EntityType.ZOMBIE || entityType == EntityType.GIANT) {
item = new ItemStack(Material.ZOMBIE_HEAD);
}
else if (entityType == EntityType.SKELETON) {
item = new ItemStack(Material.SKELETON_SKULL);
}
else if (entityType == EntityType.CREEPER) {
item = new ItemStack(Material.CREEPER_HEAD);
}
else if (entityType == EntityType.ENDER_DRAGON) {
item = new ItemStack(Material.DRAGON_HEAD);
}
else {
item = new ItemStack(Material.PLAYER_HEAD);
SkullMeta meta = (SkullMeta) item.getItemMeta();
if (meta == null) return false;
String entityName;
if (entity instanceof Player player) {
entityName = this.headName.replace(Placeholders.GENERIC_TYPE, entity.getName());
meta.setOwningPlayer(player);
}
else {
String texture = this.headTextures.get(entity.getType().name());
if (texture == null) return false;
entityName = this.headName.replace(Placeholders.GENERIC_TYPE, plugin.getLangManager().getEnum(entity.getType()));
ItemUtil.setSkullTexture(item, texture);
meta = (SkullMeta) item.getItemMeta();
}
meta.setDisplayName(entityName);
item.setItemMeta(meta);
}
entity.getWorld().dropItemNaturally(entity.getLocation(), item);
if (this.hasVisualEffects()) {
EffectUtil.playEffect(entity.getEyeLocation(), Particle.BLOCK_CRACK, Material.REDSTONE_BLOCK.name(), 0.2f, 0.15f, 0.2f, 0.15f, 40);
}
return true;
}
}

View File

@ -0,0 +1,65 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.MessageUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantDoubleStrike extends ExcellentEnchant implements Chanced, CombatEnchant {
public static final String ID = "double_strike";
private ChanceImplementation chanceImplementation;
public EnchantDoubleStrike(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.LOW);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
e.setDamage(e.getDamage() * 2D);
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.EXPLOSION_NORMAL, "", 0.2f, 0.15f, 0.2f, 0.15f, 20);
MessageUtil.sound(victim.getLocation(), Sound.ENTITY_GENERIC_EXPLODE);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,62 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantExhaust extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "exhaust";
private ChanceImplementation chanceImplementation;
public EnchantExhaust(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.HUNGER, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.addEffect(victim, level)) return false;
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.SPELL_MOB, "60,180,20", 0.2f, 0.15f, 0.2f, 0.15f, 20);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,53 +1,48 @@
package su.nightexpress.excellentenchants.manager.enchants.weapon;
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDeathEvent;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantExpHunter extends IEnchantChanceTemplate implements DeathEnchant {
private Scaler expModifier;
public class EnchantExpHunter extends ExcellentEnchant implements DeathEnchant {
public static final String ID = "exp_hunter";
public static final String PLACEHOLDER_EXP_MODIFIER = "%enchantment_exp_modifier%";
public EnchantExpHunter(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
private EnchantScaler expModifier;
public EnchantExpHunter(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.expModifier = new EnchantScaler(this, "Settings.Exp_Modifier");
this.expModifier = EnchantScaler.read(this, "Settings.Exp_Modifier", "1.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 0.5",
"Exp modifier value. The original exp amount will be multiplied on this value.");
}
public final double getExpModifier(int level) {
return this.expModifier.getValue(level);
}
@Override
protected void updateConfig() {
super.updateConfig();
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_EXP_MODIFIER, NumberUtil.format(this.getExpModifier(level) * 100D - 100D))
);
;
}
@Override
@ -57,14 +52,8 @@ public class EnchantExpHunter extends IEnchantChanceTemplate implements DeathEnc
}
@Override
public boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level) {
if (!this.isEnchantmentAvailable(dead)) return false;
Player killer = dead.getKiller();
if (killer == null) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(killer)) return false;
public boolean onKill(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, @NotNull Player killer, int level) {
if (!this.isAvailableToUse(entity)) return false;
double expModifier = this.getExpModifier(level);
double expFinal = Math.ceil((double) e.getDroppedExp() * expModifier);
@ -72,4 +61,9 @@ public class EnchantExpHunter extends IEnchantChanceTemplate implements DeathEnc
e.setDroppedExp((int) expFinal);
return true;
}
@Override
public boolean onDeath(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, int level) {
return false;
}
}

View File

@ -0,0 +1,48 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
public class EnchantIceAspect extends PotionEnchant implements CombatEnchant {
public static final String ID = "ice_aspect";
public EnchantIceAspect(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.SLOW, false);
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.addEffect(victim, level)) return false;
victim.setFreezeTicks(victim.getMaxFreezeTicks());
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.BLOCK_CRACK, Material.ICE.name(), 0.25, 0.25, 0.25, 0.1f, 30);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.weapon;
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Entity;
@ -10,49 +10,44 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.manager.EnchantManager;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantInfernus extends IEnchantChanceTemplate {
private Scaler fireTicks;
public class EnchantInfernus extends ExcellentEnchant {
public static final String ID = "infernus";
public static final String PLACEHOLDER_FIRE_DURATION = "%enchantment_fire_duration%";
public EnchantInfernus(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
private EnchantScaler fireTicks;
public EnchantInfernus(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.fireTicks = new EnchantScaler(this, "Settings.Fire_Ticks");
this.fireTicks = EnchantScaler.read(this, "Settings.Fire_Ticks", "60 + " + Placeholders.ENCHANTMENT_LEVEL + " * 20",
"Sets for how long (in ticks) entity will be ignited on hit. 20 ticks = 1 second.");
}
public int getFireTicks(int level) {
return (int) this.fireTicks.getValue(level);
}
@Override
protected void updateConfig() {
super.updateConfig();
}
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_FIRE_DURATION, NumberUtil.format((double) this.getFireTicks(level) / 20D))
);
;
}
@Override
@ -66,15 +61,13 @@ public class EnchantInfernus extends IEnchantChanceTemplate {
Entity entity = e.getEntity();
if (!(entity instanceof Trident trident)) return;
if (!(trident.getShooter() instanceof LivingEntity shooter)) return;
if (!this.isEnchantmentAvailable(shooter)) return;
if (!this.isAvailableToUse(shooter)) return;
ItemStack item = trident.getItem();
int level = EnchantManager.getItemEnchantLevel(item, this);
int level = EnchantManager.getEnchantmentLevel(item, this);
if (level <= 0) return;
if (!this.checkTriggerChance(level)) return;
if (!this.takeCostItem(shooter)) return;
trident.setFireTicks(Integer.MAX_VALUE);
}
@ -85,7 +78,7 @@ public class EnchantInfernus extends IEnchantChanceTemplate {
ItemStack item = trident.getItem();
int level = EnchantManager.getItemEnchantLevel(item, this);
int level = EnchantManager.getEnchantmentLevel(item, this);
if (level <= 0 || trident.getFireTicks() <= 0) return;
int ticks = this.getFireTicks(level);

View File

@ -0,0 +1,41 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDeathEvent;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.PlayerUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
public class EnchantNimble extends ExcellentEnchant implements DeathEnchant {
public static final String ID = "nimble";
public EnchantNimble(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.LOWEST);
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onKill(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, @NotNull Player killer, int level) {
if (!this.isAvailableToUse(entity)) return false;
e.getDrops().forEach(item -> PlayerUtil.addItem(killer, item));
e.getDrops().clear();
return true;
}
@Override
public boolean onDeath(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, int level) {
return false;
}
}

View File

@ -0,0 +1,62 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantParalyze extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "paralyze";
private ChanceImplementation chanceImplementation;
public EnchantParalyze(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.SLOW_DIGGING, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.addEffect(victim, level)) return false;
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.CRIT_MAGIC, "", 0.25, 0.25, 0.25, 0.1f, 30);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,62 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantRage extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "rage";
private ChanceImplementation chanceImplementation;
public EnchantRage(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.INCREASE_DAMAGE, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.addEffect(damager, level)) return false;
if (this.hasVisualEffects()) {
EffectUtil.playEffect(damager.getEyeLocation(), Particle.LAVA, "", 0.25, 0.25, 0.25, 0.1f, 30);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,80 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Sound;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Firework;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.utils.EntityUtil;
import su.nexmedia.engine.utils.MessageUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
public class EnchantRocket extends ExcellentEnchant implements Chanced, CombatEnchant {
public static final String ID = "rocket";
private EnchantScaler fireworkPower;
private ChanceImplementation chanceImplementation;
public EnchantRocket(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
this.fireworkPower = EnchantScaler.read(this, "Settings.Firework_Power", Placeholders.ENCHANTMENT_LEVEL + " * 0.25",
"Firework power. The more power = the higher fly distance.");
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public final double getFireworkPower(int level) {
return this.fireworkPower.getValue(level);
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (victim.isInsideVehicle()) {
victim.leaveVehicle();
}
Firework firework = EntityUtil.spawnRandomFirework(victim.getLocation());
FireworkMeta meta = firework.getFireworkMeta();
meta.setPower((int) this.getFireworkPower(level));
firework.setFireworkMeta(meta);
firework.addPassenger(victim);
MessageUtil.sound(victim.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_LAUNCH);
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.weapon;
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Material;
import org.bukkit.enchantments.EnchantmentTarget;
@ -8,32 +8,35 @@ import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.CollectionsUtil;
import su.nexmedia.engine.utils.Pair;
import su.nexmedia.engine.utils.StringUtil;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
public class EnchantScavenger extends IEnchantChanceTemplate implements DeathEnchant {
private Map<EntityType, Map<Material, Map.Entry<int[], Double>>> loot;
public class EnchantScavenger extends ExcellentEnchant implements Chanced, DeathEnchant {
public static final String ID = "scavenger";
public EnchantScavenger(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
private Map<EntityType, Map<Material, Pair<int[], Double>>> loot;
private ChanceImplementation chanceImplementation;
public EnchantScavenger(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
this.loot = new HashMap<>();
for (String eId : cfg.getSection("Settings.Treasures")) {
@ -43,7 +46,7 @@ public class EnchantScavenger extends IEnchantChanceTemplate implements DeathEnc
continue;
}
Map<Material, Map.Entry<int[], Double>> items = new HashMap<>();
Map<Material, Pair<int[], Double>> items = new HashMap<>();
for (String sFromArray : cfg.getSection("Settings.Treasures." + eId)) {
Material material = Material.getMaterial(sFromArray.toUpperCase());
if (material == null) {
@ -60,13 +63,19 @@ public class EnchantScavenger extends IEnchantChanceTemplate implements DeathEnc
double chance = cfg.getDouble(path + "Chance");
if (chance <= 0) continue;
Map.Entry<int[], Double> item = new AbstractMap.SimpleEntry<>(amount, chance);
Pair<int[], Double> item = Pair.of(amount, chance);
items.put(material, item);
}
this.loot.put(eType, items);
}
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
@ -74,23 +83,19 @@ public class EnchantScavenger extends IEnchantChanceTemplate implements DeathEnc
}
@Override
public boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level) {
if (!this.isEnchantmentAvailable(dead)) return false;
public boolean onKill(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, @NotNull Player killer, int level) {
if (!this.isAvailableToUse(entity)) return false;
Map<Material, Map.Entry<int[], Double>> items = this.loot.get(dead.getType());
Map<Material, Pair<int[], Double>> items = this.loot.get(entity.getType());
if (items == null) return false;
Player killer = dead.getKiller();
if (killer == null) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(killer)) return false;
items.forEach((material, data) -> {
double chance = data.getValue();
double chance = data.getSecond();
if (Rnd.get(true) > chance) return;
int amount = Rnd.get(data.getKey()[0], data.getKey()[1]);
int amount = Rnd.get(data.getFirst()[0], data.getFirst()[1]);
if (amount <= 0) return;
ItemStack item = new ItemStack(material);
@ -99,4 +104,9 @@ public class EnchantScavenger extends IEnchantChanceTemplate implements DeathEnc
return true;
}
@Override
public boolean onDeath(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, int level) {
return false;
}
}

View File

@ -0,0 +1,68 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantSurprise extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "surprise";
private ChanceImplementation chanceImplementation;
public EnchantSurprise(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.BLINDNESS, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public PotionEffectType getEffectType() {
return Rnd.get(PotionEffectType.values());
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.addEffect(victim, level)) return false;
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.SPELL_WITCH, "", 0.25, 0.25, 0.25, 0.1f, 30);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.weapon;
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.attribute.Attribute;
import org.bukkit.enchantments.EnchantmentTarget;
@ -6,18 +6,18 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.EntityUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantTemper extends IEnchantChanceTemplate implements CombatEnchant {
public class EnchantTemper extends ExcellentEnchant implements CombatEnchant {
public static final String ID = "temper";
public static final String PLACEHOLDER_DAMAGE_AMOUNT = "%enchantment_damage_amount%";
@ -28,16 +28,19 @@ public class EnchantTemper extends IEnchantChanceTemplate implements CombatEncha
private EnchantScaler damageCapacity;
private EnchantScaler healthPoint;
public EnchantTemper(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.MEDIUM);
public EnchantTemper(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.damageAmount = new EnchantScaler(this, "Settings.Damage.Amount");
this.damageCapacity = new EnchantScaler(this, "Settings.Damage.Capacity");
this.healthPoint = new EnchantScaler(this, "Settings.Health.Point");
this.damageAmount = EnchantScaler.read(this, "Settings.Damage.Amount", "0.01 * " + Placeholders.ENCHANTMENT_LEVEL,
"On how much (in percent) the damage will be increased per each Health Point?");
this.damageCapacity = EnchantScaler.read(this, "Settings.Damage.Capacity", "2.0",
"Maximal possible value for the Damage.Amount.");
this.healthPoint = EnchantScaler.read(this, "Settings.Health.Point", "0.5",
"For how much every missing hearts damage will be increased?");
}
public double getDamageAmount(int level) {
@ -55,11 +58,11 @@ public class EnchantTemper extends IEnchantChanceTemplate implements CombatEncha
@Override
@NotNull
public UnaryOperator<String> replacePlaceholders(int level) {
return str -> super.replacePlaceholders(level).apply(str
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_DAMAGE_AMOUNT, NumberUtil.format(this.getDamageAmount(level) * 100D))
.replace(PLACEHOLDER_DAMAGE_CAPACITY, NumberUtil.format(this.getDamageCapacity(level) * 100D))
.replace(PLACEHOLDER_HEALTH_POINT, NumberUtil.format(this.getHealthPoint(level)))
);
;
}
@NotNull
@ -69,9 +72,8 @@ public class EnchantTemper extends IEnchantChanceTemplate implements CombatEncha
}
@Override
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isEnchantmentAvailable(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
double healthPoint = this.getHealthPoint(level);
double healthHas = damager.getHealth();
@ -82,8 +84,6 @@ public class EnchantTemper extends IEnchantChanceTemplate implements CombatEncha
int pointAmount = (int) (healthDiff / healthPoint);
if (pointAmount == 0) return false;
if (!this.takeCostItem(damager)) return false;
double damageAmount = this.getDamageAmount(level);
double damageCap = this.getDamageCapacity(level);
double damageFinal = Math.min(damageCap, 1D + damageAmount * pointAmount);
@ -91,4 +91,9 @@ public class EnchantTemper extends IEnchantChanceTemplate implements CombatEncha
e.setDamage(e.getDamage() * damageFinal);
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,110 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.CollectionsUtil;
import su.nexmedia.engine.utils.PDCUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class EnchantThrifty extends ExcellentEnchant implements Chanced, DeathEnchant {
public static final String ID = "thrifty";
private Set<EntityType> ignoredEntityTypes;
private Set<CreatureSpawnEvent.SpawnReason> ignoredSpawnReasons;
private final NamespacedKey keyEntityIgnored;
private ChanceImplementation chanceImplementation;
public EnchantThrifty(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
this.keyEntityIgnored = new NamespacedKey(plugin, ID + "_ignored");
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
this.ignoredEntityTypes = JOption.create("Settings.Ignored_Entity_Types",
Set.of(EntityType.WITHER.name(), EntityType.ENDER_DRAGON.name()),
"List of entity types, that will not drop spawn eggs.",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html")
.read(cfg).stream().map(e -> CollectionsUtil.getEnum(e, EntityType.class))
.filter(Objects::nonNull).collect(Collectors.toSet());
this.ignoredSpawnReasons = JOption.create("Settings.Ignored_Spawn_Reasons",
Set.of(CreatureSpawnEvent.SpawnReason.SPAWNER_EGG.name(),
CreatureSpawnEvent.SpawnReason.SPAWNER.name(),
CreatureSpawnEvent.SpawnReason.DISPENSE_EGG.name()),
"Entities will not drop spawn eggs if they were spawned by one of the reasons below.",
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/event/entity/CreatureSpawnEvent.SpawnReason.html")
.read(cfg).stream().map(e -> CollectionsUtil.getEnum(e, CreatureSpawnEvent.SpawnReason.class))
.filter(Objects::nonNull).collect(Collectors.toSet());
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onKill(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, @NotNull Player killer, int level) {
if (!this.isAvailableToUse(entity)) return false;
if (this.ignoredEntityTypes.contains(entity.getType())) return false;
if (PDCUtil.getBooleanData(entity, this.keyEntityIgnored)) return false;
if (!this.checkTriggerChance(level)) return false;
Material material = Material.getMaterial(entity.getType().name() + "_SPAWN_EGG");
if (material == null) {
if (entity.getType() == EntityType.MUSHROOM_COW) {
material = Material.MOOSHROOM_SPAWN_EGG;
}
else return false;
}
ItemStack egg = new ItemStack(material);
e.getDrops().add(egg);
return true;
}
@Override
public boolean onDeath(@NotNull EntityDeathEvent e, @NotNull LivingEntity entity, int level) {
return false;
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onCreatureSpawn(CreatureSpawnEvent e) {
if (!this.ignoredSpawnReasons.contains(e.getSpawnReason())) return;
PDCUtil.setData(e.getEntity(), this.keyEntityIgnored, true);
}
}

View File

@ -0,0 +1,70 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
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.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantThunder extends ExcellentEnchant implements Chanced, CombatEnchant {
public static final String ID = "thunder";
private boolean inThunderstormOnly;
private ChanceImplementation chanceImplementation;
public EnchantThunder(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
this.inThunderstormOnly = JOption.create("Settings.During_Thunderstorm_Only", false,
"When 'true' the enchantment will be triggered only if there is an active thunderstorm in the world.").read(cfg);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public boolean isInThunderstormOnly() {
return inThunderstormOnly;
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (this.isInThunderstormOnly() && !victim.getWorld().isThundering()) return false;
if (victim.getLocation().getBlock().getLightFromSky() != 15) return false;
if (!this.checkTriggerChance(level)) return false;
plugin.getServer().getScheduler().runTask(plugin, () -> {
victim.setNoDamageTicks(0);
victim.getWorld().strikeLightning(victim.getLocation());
});
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -1,4 +1,4 @@
package su.nightexpress.excellentenchants.manager.enchants.weapon;
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.attribute.Attribute;
@ -8,41 +8,49 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.utils.EffectUtil;
import su.nexmedia.engine.utils.EntityUtil;
import su.nexmedia.engine.utils.NumberUtil;
import su.nexmedia.engine.utils.Scaler;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
import java.util.function.UnaryOperator;
public class EnchantVampire extends IEnchantChanceTemplate implements CombatEnchant {
private String particleName;
private String particleData;
private Scaler healAmount;
private boolean healMultiplier;
public class EnchantVampire extends ExcellentEnchant implements Chanced, CombatEnchant {
public static final String ID = "vampire";
public static final String PLACEHOLDER_HEAL_AMOUNT = "%enchantment_heal_amount%";
public EnchantVampire(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
super(plugin, cfg, EnchantPriority.LOWEST);
private EnchantScaler healAmount;
private boolean healMultiplier;
private ChanceImplementation chanceImplementation;
public EnchantVampire(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.LOWEST);
}
@Override
public void loadConfig() {
super.loadConfig();
this.particleName = cfg.getString("Settings.Particle.Name", Particle.HEART.name());
this.particleData = cfg.getString("Settings.Particle.Data", "");
this.healAmount = new EnchantScaler(this, "Settings.Heal.Amount");
this.healMultiplier = cfg.getBoolean("Settings.Heal.As_Multiplier");
this.chanceImplementation = ChanceImplementation.create(this);
this.healAmount = EnchantScaler.read(this, "Settings.Heal.Amount", "0.25 * " + Placeholders.ENCHANTMENT_LEVEL,
"Amount of health to be restored for attacker.");
this.healMultiplier = JOption.create("Settings.Heal.As_Multiplier", false,
"When 'true', the option above will work as a multiplier of the inflicted damage.").read(cfg);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
public double getHealAmount(int level) {
@ -53,18 +61,6 @@ public class EnchantVampire extends IEnchantChanceTemplate implements CombatEnch
return healMultiplier;
}
@Override
protected void updateConfig() {
super.updateConfig();
cfg.remove("Settings.Particle_Effect");
cfg.remove("Settings.Heal_Of_Damage");
cfg.addMissing("Settings.Particle.Name", Particle.HEART.name());
cfg.addMissing("Settings.Particle.Data", "");
cfg.addMissing("Settings.Heal.Amount", "0.25 * " + Placeholders.ENCHANTMENT_LEVEL);
cfg.addMissing("Settings.Heal.As_Multiplier", false);
}
@Override
@NotNull
public EnchantmentTarget getItemTarget() {
@ -76,21 +72,20 @@ public class EnchantVampire extends IEnchantChanceTemplate implements CombatEnch
public UnaryOperator<String> replacePlaceholders(int level) {
double healAmount = this.getHealAmount(level);
return str -> super.replacePlaceholders(level).apply(str
return str -> super.replacePlaceholders(level).apply(str)
.replace(PLACEHOLDER_HEAL_AMOUNT, NumberUtil.format(this.isHealMultiplier() ? healAmount * 100D : healAmount))
);
;
}
@Override
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isEnchantmentAvailable(damager)) return false;
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
double healthMax = EntityUtil.getAttribute(damager, Attribute.GENERIC_MAX_HEALTH);
double healthHas = damager.getHealth();
if (healthHas == healthMax) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.takeCostItem(damager)) return false;
double healAmount = this.getHealAmount(level);
double healFinal = this.isHealMultiplier() ? e.getDamage() * healAmount : healAmount;
@ -101,7 +96,14 @@ public class EnchantVampire extends IEnchantChanceTemplate implements CombatEnch
damager.setHealth(Math.min(healthMax, healthHas + healthEvent.getAmount()));
EffectUtil.playEffect(damager.getEyeLocation(), this.particleName, this.particleData, 0.2f, 0.15f, 0.2f, 0.15f, 5);
if (this.hasVisualEffects()) {
EffectUtil.playEffect(damager.getEyeLocation(), Particle.HEART, "", 0.2f, 0.15f, 0.2f, 0.15f, 5);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

View File

@ -0,0 +1,62 @@
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
import org.bukkit.Particle;
import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.LivingEntity;
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.EffectUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
import su.nightexpress.excellentenchants.api.enchantment.template.PotionEnchant;
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
import su.nightexpress.excellentenchants.api.enchantment.util.EnchantPriority;
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
public class EnchantVenom extends PotionEnchant implements Chanced, CombatEnchant {
public static final String ID = "venom";
private ChanceImplementation chanceImplementation;
public EnchantVenom(@NotNull ExcellentEnchants plugin) {
super(plugin, ID, EnchantPriority.MEDIUM, PotionEffectType.POISON, false);
}
@Override
public void loadConfig() {
super.loadConfig();
this.chanceImplementation = ChanceImplementation.create(this);
}
@NotNull
@Override
public ChanceImplementation getChanceImplementation() {
return chanceImplementation;
}
@NotNull
@Override
public EnchantmentTarget getItemTarget() {
return EnchantmentTarget.WEAPON;
}
@Override
public boolean onAttack(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
if (!this.isAvailableToUse(damager)) return false;
if (!this.checkTriggerChance(level)) return false;
if (!this.addEffect(victim, level)) return false;
if (this.hasVisualEffects()) {
EffectUtil.playEffect(victim.getEyeLocation(), Particle.SLIME, "", 0.25, 0.25, 0.25, 0.1f, 30);
}
return true;
}
@Override
public boolean onProtect(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
return false;
}
}

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