mirror of
https://github.com/nulli0n/ExcellentEnchants-spigot.git
synced 2025-01-17 20:21:26 +01:00
3.1.0
This commit is contained in:
commit
ab5b19db4d
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/Core/pom.xml.versionsBackup
|
||||
/pom.xml.versionsBackup
|
||||
/NMS/pom.xml.versionsBackup
|
||||
/V1_16_R1/pom.xml.versionsBackup
|
||||
/V1_17_R1/pom.xml.versionsBackup
|
||||
/V1_18_R1/pom.xml.versionsBackup
|
||||
/Core/target/
|
||||
/NMS/target/
|
||||
/V1_16_R1/target/
|
||||
/V1_17_R1/target/
|
||||
/V1_18_R1/target/
|
||||
/.idea/
|
||||
/target/
|
92
Core/pom.xml
Normal file
92
Core/pom.xml
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ExcellentEnchants</artifactId>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<version>3.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>Core</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>md_5-releases</id>
|
||||
<url>https://repo.md-5.net/content/repositories/releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.18.1-R0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>NMS</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>V1_16_R1</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>V1_17_R1</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>V1_18_R1</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.neatmonster</groupId>
|
||||
<artifactId>nocheatplus</artifactId>
|
||||
<version>3.16.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory> <!-- (your resources folder location) -->
|
||||
<filtering>true</filtering> <!-- this is the important part, it's what replaces, filters, all placeholders in the resources folder (such as ${project.version} in plugin.yml) -->
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputFile>${project.parent.basedir}\target\${project.parent.name}-${project.version}.jar</outputFile>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>su.nightexpress.excellentenchants*</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,122 @@
|
||||
package su.nightexpress.excellentenchants;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.NexPlugin;
|
||||
import su.nexmedia.engine.Version;
|
||||
import su.nexmedia.engine.api.command.GeneralCommand;
|
||||
import su.nexmedia.engine.utils.Reflex;
|
||||
import su.nightexpress.excellentenchants.command.BookCommand;
|
||||
import su.nightexpress.excellentenchants.command.EnchantCommand;
|
||||
import su.nightexpress.excellentenchants.command.ListCommand;
|
||||
import su.nightexpress.excellentenchants.command.TierbookCommand;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
import su.nightexpress.excellentenchants.config.Lang;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantManager;
|
||||
import su.nightexpress.excellentenchants.nms.EnchantNMS;
|
||||
|
||||
public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
|
||||
|
||||
private static ExcellentEnchants instance;
|
||||
|
||||
public static boolean isLoaded = false;
|
||||
|
||||
private Config config;
|
||||
private Lang lang;
|
||||
|
||||
private EnchantNMS enchantNMS;
|
||||
private EnchantManager enchantManager;
|
||||
|
||||
public ExcellentEnchants() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static ExcellentEnchants getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
if (!this.setNMS()) {
|
||||
this.error("Could not setup internal NMS handler!");
|
||||
this.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.enchantManager = new EnchantManager(this);
|
||||
this.enchantManager.setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
if (this.enchantManager != null) {
|
||||
this.enchantManager.shutdown();
|
||||
this.enchantManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useNewConfigFields() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean setNMS() {
|
||||
Version current = Version.CURRENT;
|
||||
if (current == null) return false;
|
||||
|
||||
String pack = EnchantNMS.class.getPackage().getName();
|
||||
Class<?> clazz = Reflex.getClass(pack, current.name());
|
||||
if (clazz == null) return false;
|
||||
|
||||
try {
|
||||
this.enchantNMS = (EnchantNMS) clazz.getConstructor().newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this.enchantNMS != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfig() {
|
||||
this.config = new Config(this);
|
||||
this.config.setup();
|
||||
|
||||
this.lang = new Lang(this);
|
||||
this.lang.setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands(@NotNull GeneralCommand<ExcellentEnchants> mainCommand) {
|
||||
mainCommand.addChildren(new BookCommand(this));
|
||||
mainCommand.addChildren(new EnchantCommand(this));
|
||||
mainCommand.addChildren(new ListCommand(this));
|
||||
mainCommand.addChildren(new TierbookCommand(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerHooks() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Config cfg() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Lang lang() {
|
||||
return this.lang;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantManager getEnchantManager() {
|
||||
return this.enchantManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantNMS getEnchantNMS() {
|
||||
return enchantNMS;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package su.nightexpress.excellentenchants;
|
||||
|
||||
public class Perms {
|
||||
|
||||
public static final String PREFIX = "excellentenchants.";
|
||||
|
||||
public static final String ADMIN = PREFIX + "admin";
|
||||
public static final String USER = PREFIX + "user";
|
||||
|
||||
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";
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
public enum EnchantPriority {
|
||||
|
||||
LOWEST, LOW, MEDIUM, HIGH, HIGHEST
|
||||
}
|
@ -0,0 +1,308 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
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.JYML;
|
||||
import su.nexmedia.engine.api.manager.IListener;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.*;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
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 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 static final String PLACEHOLDER_NAME = "%enchantment_name%";
|
||||
public static final String PLACEHLDER_NAME_FORMATTED = "%enchantment_name_formatted%";
|
||||
public static final String PLACEHOLDER_DESCRIPTION = "%enchantment_description%";
|
||||
public static final String PLACEHOLDER_LEVEL = "%enchantment_level%";
|
||||
public static final String PLACEHOLDER_LEVEL_MIN = "%enchantment_level_min%";
|
||||
public static final String PLACEHOLDER_LEVEL_MAX = "%enchantment_level_max%";
|
||||
public static final String PLACEHOLDER_CONFLICTS = "%enchantment_conflicts%";
|
||||
public static final String PLACEHOLDER_TARGET = "%enchantment_target%";
|
||||
public static final String PLACEHOLDER_TIER = "%enchantment_tier%";
|
||||
public static final String PLACEHOLDER_FIT_ITEM_TYPES = "%enchantment_fit_item_types%";
|
||||
public static final String PLACEHOLDER_OBTAIN_CHANCE_ENCHANTING = "%enchantment_obtain_chance_enchanting%";
|
||||
public static final String PLACEHOLDER_OBTAIN_CHANCE_VILLAGER = "%enchantment_obtain_chance_villager%";
|
||||
public static final String PLACEHOLDER_OBTAIN_CHANCE_LOOT_GENERATION = "%enchantment_obtain_chance_loot_generation%";
|
||||
public static final String PLACEHOLDER_OBTAIN_CHANCE_FISHING = "%enchantment_obtain_chance_fishing%";
|
||||
public static final String PLACEHOLDER_OBTAIN_CHANCE_MOB_SPAWNING = "%enchantment_obtain_chance_mob_spawning%";
|
||||
public static final String PLACEHOLDER_COST_ITEM = "%enchantment_cost_item%";
|
||||
|
||||
protected final ExcellentEnchants plugin;
|
||||
protected final JYML cfg;
|
||||
protected final String id;
|
||||
protected final EnchantPriority priority;
|
||||
|
||||
protected String displayName;
|
||||
protected EnchantTier tier;
|
||||
protected List<String> description;
|
||||
|
||||
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 ItemStack costItem;
|
||||
protected boolean costEnabled;
|
||||
|
||||
public ExcellentEnchant(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg, @NotNull EnchantPriority priority) {
|
||||
super(NamespacedKey.minecraft(cfg.getFile().getName().replace(".yml", "").toLowerCase()));
|
||||
this.plugin = plugin;
|
||||
this.id = this.getKey().getKey();
|
||||
this.cfg = cfg;
|
||||
this.updateConfig();
|
||||
this.cfg.saveChanges();
|
||||
this.priority = priority;
|
||||
|
||||
this.displayName = StringUtil.color(cfg.getString("Name", this.getId()));
|
||||
this.tier = EnchantManager.getTierById(cfg.getString("Tier", Constants.DEFAULT));
|
||||
if (this.tier == null) {
|
||||
throw new IllegalStateException("Invalid tier provided for the '" + id + "' enchantment!");
|
||||
}
|
||||
this.tier.getEnchants().add(this);
|
||||
this.description = StringUtil.color(cfg.getStringList("Description"));
|
||||
|
||||
this.conflicts = new HashSet<>();
|
||||
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.obtainChance = new HashMap<>();
|
||||
for (ObtainType obtainType : ObtainType.values()) {
|
||||
double obtainChance = cfg.getDouble(obtainType.getPathName() + ".Chance");
|
||||
this.obtainChance.put(obtainType, obtainChance);
|
||||
}
|
||||
|
||||
this.costEnabled = cfg.getBoolean("Settings.Cost.Enabled");
|
||||
this.costItem = cfg.getItem("Settings.Cost.Item");
|
||||
}
|
||||
|
||||
protected void updateConfig() {
|
||||
cfg.addMissing("Is_Treasure", false);
|
||||
cfg.addMissing("Settings.Cost.Enabled", false);
|
||||
cfg.addMissing("Settings.Cost.Item.Material", Material.AIR.name());
|
||||
cfg.addMissing("Settings.Cost.Item.Amount", 1);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
for (ObtainType obtainType : ObtainType.values()) {
|
||||
cfg.addMissing(obtainType.getPathName() + ".Chance", 25D);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
String conflicts = this.getConflicts().isEmpty() ? plugin.lang().Other_None.getMsg() : this.getConflicts().stream().filter(Objects::nonNull).map(en -> plugin.lang().getEnchantment(en)).collect(Collectors.joining("\n"));
|
||||
|
||||
return str -> str
|
||||
.replace(PLACEHOLDER_NAME, this.getDisplayName())
|
||||
.replace(PLACEHLDER_NAME_FORMATTED, this.getNameFormatted(level))
|
||||
.replace(PLACEHOLDER_LEVEL, NumberUtil.toRoman(level))
|
||||
.replace(PLACEHOLDER_LEVEL_MIN, String.valueOf(this.getStartLevel()))
|
||||
.replace(PLACEHOLDER_LEVEL_MAX, String.valueOf(this.getMaxLevel()))
|
||||
.replace(PLACEHOLDER_TARGET, plugin.lang().getEnum(this.getItemTarget()))
|
||||
.replace(PLACEHOLDER_TIER, this.getTier().getName())
|
||||
.replace(PLACEHOLDER_CONFLICTS, conflicts)
|
||||
.replace(PLACEHOLDER_FIT_ITEM_TYPES, String.join(", ", Stream.of(this.getFitItemTypes()).map(type -> plugin.lang().getEnum(type)).toList()))
|
||||
.replace(PLACEHOLDER_OBTAIN_CHANCE_ENCHANTING, NumberUtil.format(this.getObtainChance(ObtainType.ENCHANTING)))
|
||||
.replace(PLACEHOLDER_OBTAIN_CHANCE_VILLAGER, NumberUtil.format(this.getObtainChance(ObtainType.VILLAGER)))
|
||||
.replace(PLACEHOLDER_OBTAIN_CHANCE_LOOT_GENERATION, NumberUtil.format(this.getObtainChance(ObtainType.LOOT_GENERATION)))
|
||||
.replace(PLACEHOLDER_OBTAIN_CHANCE_FISHING, NumberUtil.format(this.getObtainChance(ObtainType.FISHING)))
|
||||
.replace(PLACEHOLDER_OBTAIN_CHANCE_MOB_SPAWNING, NumberUtil.format(this.getObtainChance(ObtainType.MOB_SPAWNING)))
|
||||
.replace(PLACEHOLDER_COST_ITEM, this.hasCostItem() ? ItemUtil.getItemName(this.costItem) : plugin.lang().Other_None.getMsg())
|
||||
;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public UnaryOperator<String> formatString(int level) {
|
||||
return str -> this.replacePlaceholders(level).apply(str
|
||||
.replace(PLACEHOLDER_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};
|
||||
}
|
||||
|
||||
protected void addConflicts() {
|
||||
|
||||
}
|
||||
|
||||
protected void addConflict(@NotNull Enchantment enchantment) {
|
||||
this.conflicts.add(enchantment);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
this.addConflicts();
|
||||
this.plugin.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JYML getConfig() {
|
||||
return this.cfg;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantPriority getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getId().toUpperCase();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getNameFormatted(int level) {
|
||||
return this.getTier().getColor() + this.getDisplayName() + " " + NumberUtil.toRoman(level);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getDescription(int level) {
|
||||
List<String> description = new ArrayList<>(this.description);
|
||||
description.replaceAll(this.replacePlaceholders(level));
|
||||
return description;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<Enchantment> getConflicts() {
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantTier getTier() {
|
||||
return this.tier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLevel() {
|
||||
return this.levelMax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartLevel() {
|
||||
return this.levelMin;
|
||||
}
|
||||
|
||||
public int getLevelByEnchantCost(int expLevel) {
|
||||
Optional<Map.Entry<Integer, Double>> opt = this.levelByEnchantCost.getValues().entrySet().stream().filter(en -> expLevel >= en.getValue().intValue()).max(Comparator.comparingInt(Map.Entry::getKey));
|
||||
return opt.isPresent() ? opt.get().getKey() : Rnd.get(this.getStartLevel(), this.getMaxLevel());
|
||||
}
|
||||
|
||||
public double getObtainChance(@NotNull ObtainType obtainType) {
|
||||
return this.obtainChance.getOrDefault(obtainType, 0D);
|
||||
}
|
||||
|
||||
public int getAnvilMergeCost(int level) {
|
||||
return (int) this.anvilMergeCost.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean conflictsWith(@NotNull Enchantment enchantment) {
|
||||
return this.conflicts.contains(enchantment);
|
||||
}
|
||||
|
||||
@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 (!item.containsEnchantment(this) && EnchantManager.getItemCustomEnchantsAmount(item) >= Config.ENCHANTMENTS_ITEM_CUSTOM_MAX) {
|
||||
return false;
|
||||
}
|
||||
if (item.getType() == Material.BOOK || item.getType() == Material.ENCHANTED_BOOK) {
|
||||
return true;
|
||||
}
|
||||
return Stream.of(this.getFitItemTypes()).anyMatch(fitItemType -> fitItemType.isIncluded(item));
|
||||
}
|
||||
|
||||
/*protected boolean isFitItemType(@NotNull ItemStack item) {
|
||||
EnchantmentTarget target = this.getItemTarget();
|
||||
return switch (target) {
|
||||
case ARMOR -> ItemUtil.isArmor(item);
|
||||
case ARMOR_FEET -> ItemUtil.isBoots(item);
|
||||
case ARMOR_LEGS -> ItemUtil.isLeggings(item);
|
||||
case ARMOR_TORSO -> ItemUtil.isChestplate(item) || (Config.ENCHANTMENTS_ITEM_ELYTRA_AS_CHESTPLATE && item.getType() == Material.ELYTRA);
|
||||
case ARMOR_HEAD -> ItemUtil.isHelmet(item);
|
||||
case WEAPON -> ItemUtil.isSword(item) || (Config.ENCHANTMENTS_ITEM_AXES_AS_SWORDS && ItemUtil.isAxe(item));
|
||||
case TOOL -> ItemUtil.isTool(item);
|
||||
case BOW -> item.getType() == Material.BOW || (Config.ENCHANTMENTS_ITEM_CROSSBOWS_AS_BOWS && ItemUtil.isBow(item));
|
||||
case FISHING_ROD -> item.getType() == Material.FISHING_ROD;
|
||||
case BREAKABLE -> true;
|
||||
case WEARABLE -> EnchantManager.isEnchantable(item);
|
||||
case TRIDENT -> ItemUtil.isTrident(item);
|
||||
case CROSSBOW -> item.getType() == Material.CROSSBOW;
|
||||
default -> false;
|
||||
};
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public boolean isCursed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isTreasure() {
|
||||
return this.isTreasure;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
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;
|
||||
|
||||
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 (!bow.containsEnchantment(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;
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
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.tasks.ArrowTrailsTask;
|
||||
|
||||
public abstract class IEnchantBowTemplate extends IEnchantChanceTemplate implements BowEnchant {
|
||||
|
||||
protected final String arrowTrailName;
|
||||
protected final 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";
|
||||
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 (!bow.containsEnchantment(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;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
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);
|
||||
|
||||
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%", PLACEHOLDER_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);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
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.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
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 Scaler potionDuration;
|
||||
protected Scaler potionLevel;
|
||||
protected final boolean potionParticles;
|
||||
|
||||
public IEnchantPotionTemplate(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg,
|
||||
@NotNull EnchantPriority priority,
|
||||
@NotNull PotionEffectType potionEffectType) {
|
||||
super(plugin, cfg, priority);
|
||||
this.potionEffectType = potionEffectType;
|
||||
this.potionDuration = new EnchantScaler(this, "Settings.Potion_Effect.Duration");
|
||||
this.potionLevel = new EnchantScaler(this, "Settings.Potion_Effect.Level");
|
||||
this.potionParticles = !(this instanceof PassiveEnchant);
|
||||
}
|
||||
|
||||
@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, plugin.lang().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 addEffect(@NotNull LivingEntity target, int level) {
|
||||
EnchantManager.addPotionEffect(target, this.getEffect(level), true);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface BlockBreakEnchant {
|
||||
|
||||
boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface BowEnchant extends CombatEnchant {
|
||||
|
||||
boolean use(@NotNull EntityShootBowEvent e, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level);
|
||||
|
||||
boolean use(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface CombatEnchant {
|
||||
|
||||
boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CustomDropEnchant {
|
||||
|
||||
@NotNull List<ItemStack> getCustomDrops(@NotNull Player player, @NotNull ItemStack item, @NotNull Block block, int level);
|
||||
|
||||
boolean isEventMustHaveDrops();
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface DeathEnchant {
|
||||
|
||||
boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface InteractEnchant {
|
||||
|
||||
boolean use(@NotNull PlayerInteractEvent e, @NotNull Player player, @NotNull ItemStack item, int level);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
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);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface PassiveEnchant {
|
||||
|
||||
boolean use(@NotNull LivingEntity entity, int level);
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package su.nightexpress.excellentenchants.command;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.command.AbstractCommand;
|
||||
import su.nexmedia.engine.utils.PlayerUtil;
|
||||
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.manager.EnchantManager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class BookCommand extends AbstractCommand<ExcellentEnchants> {
|
||||
|
||||
public BookCommand(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, new String[]{"book"}, Perms.COMMAND_BOOK);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDescription() {
|
||||
return plugin.lang().Command_Book_Desc.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getUsage() {
|
||||
return plugin.lang().Command_Book_Usage.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<String> getTab(@NotNull Player player, int i, @NotNull String[] args) {
|
||||
if (i == 1) {
|
||||
return PlayerUtil.getPlayerNames();
|
||||
}
|
||||
if (i == 2) {
|
||||
return Arrays.stream(Enchantment.values()).map(e -> e.getKey().getKey()).toList();
|
||||
}
|
||||
if (i == 3) {
|
||||
return Arrays.asList("-1", "1", "5", "10");
|
||||
}
|
||||
return super.getTab(player, i, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
|
||||
if (args.length != 4) {
|
||||
this.printUsage(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = plugin.getServer().getPlayer(args[1]);
|
||||
if (player == null) {
|
||||
this.errorPlayer(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(args[2].toLowerCase()));
|
||||
if (enchantment == null) {
|
||||
plugin.lang().Error_NoEnchant.send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
int level = StringUtil.getInteger(args[3], -1, true);
|
||||
if (level < 1) {
|
||||
level = Rnd.get(enchantment.getStartLevel(), enchantment.getMaxLevel());
|
||||
}
|
||||
|
||||
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);
|
||||
PlayerUtil.addItem(player, item);
|
||||
|
||||
plugin.lang().Command_Book_Done
|
||||
.replace("%enchant%", plugin.lang().getEnchantment(enchantment))
|
||||
.replace("%player%", player.getName()).send(sender);
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package su.nightexpress.excellentenchants.command;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.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;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Perms;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantManager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class EnchantCommand extends AbstractCommand<ExcellentEnchants> {
|
||||
|
||||
public EnchantCommand(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, new String[]{"enchant"}, Perms.COMMAND_ENCHANT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDescription() {
|
||||
return plugin.lang().Command_Enchant_Desc.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getUsage() {
|
||||
return plugin.lang().Command_Enchant_Usage.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<String> getTab(@NotNull Player player, int i, @NotNull String[] args) {
|
||||
if (i == 1) {
|
||||
return Arrays.stream(Enchantment.values()).map(e -> e.getKey().getKey()).toList();
|
||||
}
|
||||
if (i == 2) {
|
||||
return Arrays.asList("-1", "1", "5", "10");
|
||||
}
|
||||
return super.getTab(player, i, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
|
||||
if (args.length != 3) {
|
||||
this.printUsage(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = (Player) sender;
|
||||
ItemStack item = player.getInventory().getItemInMainHand();
|
||||
if (item.getType().isAir()) {
|
||||
this.errorItem(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(args[1].toLowerCase()));
|
||||
if (enchantment == null) {
|
||||
plugin.lang().Error_NoEnchant.send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
int level = StringUtil.getInteger(args[2], -1, true);
|
||||
if (level < 0) {
|
||||
level = Rnd.get(enchantment.getStartLevel(), enchantment.getMaxLevel());
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) return;
|
||||
|
||||
if (meta instanceof EnchantmentStorageMeta) {
|
||||
if (level == 0) {
|
||||
((EnchantmentStorageMeta) meta).removeStoredEnchant(enchantment);
|
||||
}
|
||||
else {
|
||||
((EnchantmentStorageMeta) meta).addStoredEnchant(enchantment, level, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (level == 0) {
|
||||
meta.removeEnchant(enchantment);
|
||||
}
|
||||
else {
|
||||
meta.addEnchant(enchantment, level, true);
|
||||
}
|
||||
}
|
||||
item.setItemMeta(meta);
|
||||
EnchantManager.updateItemLoreEnchants(item);
|
||||
|
||||
plugin.lang().Command_Enchant_Done.send(sender);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package su.nightexpress.excellentenchants.command;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.command.AbstractCommand;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Perms;
|
||||
|
||||
public class ListCommand extends AbstractCommand<ExcellentEnchants> {
|
||||
|
||||
public ListCommand(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, new String[]{"list"}, Perms.COMMAND_LIST);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getUsage() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDescription() {
|
||||
return plugin.lang().Command_List_Desc.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
|
||||
plugin.getEnchantManager().getEnchantsListGUI().open((Player) sender, 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package su.nightexpress.excellentenchants.command;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.command.AbstractCommand;
|
||||
import su.nexmedia.engine.utils.PlayerUtil;
|
||||
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.api.enchantment.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantManager;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantTier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class TierbookCommand extends AbstractCommand<ExcellentEnchants> {
|
||||
|
||||
public TierbookCommand(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, new String[]{"tierbook"}, Perms.COMMAND_TIERBOOK);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDescription() {
|
||||
return plugin.lang().Command_TierBook_Desc.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getUsage() {
|
||||
return plugin.lang().Command_TierBook_Usage.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<String> getTab(@NotNull Player player, int i, @NotNull String[] args) {
|
||||
if (i == 1) {
|
||||
return PlayerUtil.getPlayerNames();
|
||||
}
|
||||
if (i == 2) {
|
||||
return EnchantManager.getTierIds();
|
||||
}
|
||||
if (i == 3) {
|
||||
return Arrays.asList("-1", "1", "5", "10");
|
||||
}
|
||||
return super.getTab(player, i, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
|
||||
if (args.length != 4) {
|
||||
this.printUsage(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = plugin.getServer().getPlayer(args[1]);
|
||||
if (player == null) {
|
||||
this.errorPlayer(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
EnchantTier tier = EnchantManager.getTierById(args[2].toLowerCase());
|
||||
if (tier == null) {
|
||||
plugin.lang().Command_TierBook_Error.send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
ExcellentEnchant enchant = Rnd.get(tier.getEnchants());
|
||||
if (enchant == null) {
|
||||
plugin.lang().Error_NoEnchant.send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
int level = StringUtil.getInteger(args[3], -1, true);
|
||||
if (level < 1) {
|
||||
level = Rnd.get(enchant.getStartLevel(), enchant.getMaxLevel());
|
||||
}
|
||||
|
||||
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
|
||||
EnchantManager.addEnchant(item, enchant, level, true);
|
||||
PlayerUtil.addItem(player, item);
|
||||
|
||||
plugin.lang().Command_TierBook_Done
|
||||
.replace("%tier%", tier.getName())
|
||||
.replace("%player%", player.getName()).send(sender);
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
package su.nightexpress.excellentenchants.config;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.api.config.ConfigTemplate;
|
||||
import su.nexmedia.engine.utils.Constants;
|
||||
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 java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Config extends ConfigTemplate {
|
||||
|
||||
public Config(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
public static long TASKS_ARROW_TRAIL_TICKS_INTERVAL;
|
||||
public static long TASKS_PASSIVE_ENCHANTS_TICKS_INTERVAL;
|
||||
|
||||
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 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;
|
||||
|
||||
private static Map<ObtainType, ObtainSettings> OBTAIN_SETTINGS;
|
||||
private static Map<String, EnchantTier> TIERS;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
String path = "General.Tasks.";
|
||||
TASKS_ARROW_TRAIL_TICKS_INTERVAL = cfg.getLong(path + "Arrow_Trails.Ticks_Interval", 1);
|
||||
TASKS_PASSIVE_ENCHANTS_TICKS_INTERVAL = cfg.getLong(path + "Passive_Enchants.Ticks_Interval", 100);
|
||||
|
||||
path = "General.Enchantments.";
|
||||
cfg.addMissing(path + "Disabled_In_Worlds.my_world", Collections.singletonList(Constants.MASK_ANY));
|
||||
cfg.addMissing(path + "Disabled_In_Worlds.other_world", Arrays.asList("enchant_name", "another_enchant"));
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
ENCHANTMENTS_DESCRIPTION_ENABLED = cfg.getBoolean(path + "Description.Enabled");
|
||||
ENCHANTMENTS_DESCRIPTION_FORMAT = StringUtil.color(cfg.getString(path + "Description.Format", ""));
|
||||
|
||||
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");
|
||||
|
||||
path = "General.Enchantments.Entity.";
|
||||
ENCHANTMENTS_ENTITY_PASSIVE_FOR_MOBS = cfg.getBoolean(path + "Passive_Enchants_Applied_To_Mobs");
|
||||
|
||||
OBTAIN_SETTINGS = new HashMap<>();
|
||||
for (ObtainType obtainType : ObtainType.values()) {
|
||||
String path2 = "General." + obtainType.getPathName() + ".";
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
this.setupTiers();
|
||||
}
|
||||
|
||||
private void setupTiers() {
|
||||
// Reloading tiers will reset their lists with enchants = break the plugin mechanics
|
||||
if (ExcellentEnchants.isLoaded) return;
|
||||
|
||||
TIERS = new HashMap<>();
|
||||
|
||||
// No tiers defined, setup a default one.
|
||||
// Every enchantment must have a tier.
|
||||
if (cfg.getSection("Tiers").isEmpty()) {
|
||||
this.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);
|
||||
}
|
||||
|
||||
this.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(Constants.MASK_ANY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EnchantTier getTierById(@NotNull String id) {
|
||||
return TIERS.get(id.toLowerCase());
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package su.nightexpress.excellentenchants.config;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.LangMessage;
|
||||
import su.nexmedia.engine.core.config.CoreLang;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
public class Lang extends CoreLang {
|
||||
|
||||
public Lang(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
super.setup();
|
||||
this.setupEnum(EnchantmentTarget.class);
|
||||
this.setupEnum(FitItemType.class);
|
||||
}
|
||||
|
||||
public LangMessage Command_List_Desc = new LangMessage(this, "List of all custom enchantments.");
|
||||
|
||||
public LangMessage Command_Enchant_Usage = new LangMessage(this, "<enchant> <level>");
|
||||
public LangMessage Command_Enchant_Desc = new LangMessage(this, "Enchants the item in your hand.");
|
||||
public LangMessage Command_Enchant_Done = new LangMessage(this, "&aSuccessfully enchanted!");
|
||||
|
||||
public LangMessage Command_Book_Usage = new LangMessage(this, "<player> <enchant> <level>");
|
||||
public LangMessage Command_Book_Desc = new LangMessage(this, "Gives custom enchanted book.");
|
||||
public LangMessage Command_Book_Done = new LangMessage(this, "Given &6%enchant%&7 enchanted book to &6%player%&7.");
|
||||
|
||||
public LangMessage Command_TierBook_Usage = new LangMessage(this, "<player> <tier> <level>");
|
||||
public LangMessage Command_TierBook_Desc = new LangMessage(this, "Gives an enchanted book.");
|
||||
public LangMessage Command_TierBook_Error = new LangMessage(this, "&cInvalid tier!");
|
||||
public LangMessage Command_TierBook_Done = new LangMessage(this, "Given &6%tier%&7 enchanted book to &6%player%&7.");
|
||||
|
||||
public LangMessage Error_NoEnchant = new LangMessage(this, "&cNo such enchant.");
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package su.nightexpress.excellentenchants.config;
|
||||
|
||||
public class ObtainSettings {
|
||||
|
||||
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) {
|
||||
this.enchantsTotalMax = enchantsTotalMax;
|
||||
this.enchantsCustomGenerationChance = enchantsCustomGenerationChance;
|
||||
this.enchantsCustomMin = enchantsCustomMin;
|
||||
this.enchantsCustomMax = enchantsCustomMax;
|
||||
}
|
||||
|
||||
public int getEnchantsTotalMax() {
|
||||
return enchantsTotalMax;
|
||||
}
|
||||
|
||||
public double getEnchantsCustomGenerationChance() {
|
||||
return enchantsCustomGenerationChance;
|
||||
}
|
||||
|
||||
public int getEnchantsCustomMin() {
|
||||
return enchantsCustomMin;
|
||||
}
|
||||
|
||||
public int getEnchantsCustomMax() {
|
||||
return enchantsCustomMax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ObtainSettings{" + "enchantsTotalMax=" + enchantsTotalMax + ", enchantsCustomGenerationChance=" + enchantsCustomGenerationChance + ", enchantsCustomMin=" + enchantsCustomMin + ", enchantsCustomMax=" + enchantsCustomMax + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package su.nightexpress.excellentenchants.hook;
|
||||
|
||||
public class HookId {
|
||||
|
||||
public static final String NCP = "NoCheatPlus";
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package su.nightexpress.excellentenchants.hook;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.hooks.ExemptionContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.hooks.Hooks;
|
||||
|
||||
public class HookNCP {
|
||||
|
||||
public static void exemptBlocks(@NotNull Player player) {
|
||||
if (!Hooks.hasPlugin(HookId.NCP)) return;
|
||||
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getPlayerDataManager().getPlayerData(player).exempt(CheckType.BLOCKBREAK, ExemptionContext.ANONYMOUS_NESTED);
|
||||
}
|
||||
|
||||
public static void unexemptBlocks(@NotNull Player player) {
|
||||
if (!Hooks.hasPlugin(HookId.NCP)) return;
|
||||
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getPlayerDataManager().getPlayerData(player).unexempt(CheckType.BLOCKBREAK, ExemptionContext.ANONYMOUS_NESTED);
|
||||
}
|
||||
}
|
@ -0,0 +1,259 @@
|
||||
package su.nightexpress.excellentenchants.manager;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.api.manager.AbstractManager;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
|
||||
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.EnchantTier;
|
||||
import su.nightexpress.excellentenchants.manager.tasks.ArrowTrailsTask;
|
||||
import su.nightexpress.excellentenchants.manager.tasks.EnchantEffectPassiveTask;
|
||||
import su.nightexpress.excellentenchants.manager.type.ObtainType;
|
||||
|
||||
import java.util.*;
|
||||
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 static final Map<UUID, ItemStack> PROJECTILE_WEAPON = new HashMap<>();
|
||||
|
||||
public EnchantManager(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
EnchantRegister.setup();
|
||||
|
||||
this.enchantListGUI = new EnchantListGUI(this.plugin);
|
||||
this.addListener(new EnchantHandlerListener(this));
|
||||
this.addListener(new EnchantGenericListener(this));
|
||||
|
||||
this.arrowTrailsTask = new ArrowTrailsTask(this.plugin);
|
||||
this.arrowTrailsTask.start();
|
||||
|
||||
this.enchantEffectPassiveTask = new EnchantEffectPassiveTask(this.plugin);
|
||||
this.enchantEffectPassiveTask.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShutdown() {
|
||||
if (this.enchantListGUI != null) {
|
||||
this.enchantListGUI.clear();
|
||||
this.enchantListGUI = null;
|
||||
}
|
||||
if (this.arrowTrailsTask != null) {
|
||||
this.arrowTrailsTask.stop();
|
||||
this.arrowTrailsTask = null;
|
||||
}
|
||||
if (this.enchantEffectPassiveTask != null) {
|
||||
this.enchantEffectPassiveTask.stop();
|
||||
this.enchantEffectPassiveTask = null;
|
||||
}
|
||||
EnchantRegister.shutdown();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantListGUI getEnchantsListGUI() {
|
||||
return enchantListGUI;
|
||||
}
|
||||
|
||||
public static void addPotionEffect(@NotNull LivingEntity entity, @NotNull PotionEffect effect, boolean compat) {
|
||||
if (compat) {
|
||||
PotionEffect has = entity.getPotionEffect(effect.getType());
|
||||
if (has != null && has.getAmplifier() > effect.getAmplifier()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
entity.removePotionEffect(effect.getType());
|
||||
}
|
||||
entity.addPotionEffect(effect);
|
||||
}
|
||||
|
||||
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)*/;
|
||||
}
|
||||
|
||||
public static boolean populateEnchantments(@NotNull ItemStack item, @NotNull ObtainType obtainType) {
|
||||
ObtainSettings settings = Config.getObtainSettings(obtainType);
|
||||
if (settings == null) return false;
|
||||
|
||||
if (Rnd.get(true) > settings.getEnchantsCustomGenerationChance()) return false;
|
||||
|
||||
int enchHas = EnchantManager.getItemEnchantsAmount(item);
|
||||
int enchMax = settings.getEnchantsTotalMax();
|
||||
int enchRoll = Rnd.get(settings.getEnchantsCustomMin(), settings.getEnchantsCustomMax());
|
||||
|
||||
for (int count = 0; (count < enchRoll && count + enchHas < enchMax); count++) {
|
||||
EnchantTier tier = EnchantManager.getTierByChance(obtainType);
|
||||
if (tier == null) continue;
|
||||
|
||||
ExcellentEnchant enchant = tier.getEnchant(obtainType, item);
|
||||
if (enchant == null) continue;
|
||||
|
||||
int level = Rnd.get(enchant.getStartLevel(), enchant.getMaxLevel());
|
||||
EnchantManager.addEnchant(item, enchant, level, false);
|
||||
}
|
||||
EnchantManager.updateItemLoreEnchants(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static boolean hasEnchant(@NotNull ItemStack item, @NotNull Enchantment enchantment) {
|
||||
return item.getEnchantmentLevel(enchantment) != 0;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static int getEnchantLevel(@NotNull ItemStack item, @NotNull Enchantment enchantment) {
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
return meta != null ? meta.getEnchantLevel(enchantment) : item.getEnchantmentLevel(enchantment);
|
||||
}
|
||||
|
||||
public static void updateItemLoreEnchants(@NotNull ItemStack item) {
|
||||
EnchantRegister.ENCHANT_LIST.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 ExcellentEnchant ench, int level, boolean force) {
|
||||
if (!force && !ench.canEnchantItem(item)) return false;
|
||||
|
||||
EnchantManager.removeEnchant(item, ench);
|
||||
ItemUtil.addLore(item, ench.getId(), ench.getNameFormatted(level), 0);
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) return false;
|
||||
|
||||
if (meta instanceof EnchantmentStorageMeta meta2) {
|
||||
if (!meta2.addStoredEnchant(ench, level, true)) return false;
|
||||
}
|
||||
else {
|
||||
if (!meta.addEnchant(ench, level, true)) return false;
|
||||
}
|
||||
item.setItemMeta(meta);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void removeEnchant(@NotNull ItemStack item, @NotNull ExcellentEnchant en) {
|
||||
ItemUtil.delLore(item, en.getId());
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta instanceof EnchantmentStorageMeta meta2) {
|
||||
meta2.removeStoredEnchant(en);
|
||||
}
|
||||
else {
|
||||
meta.removeEnchant(en);
|
||||
}
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
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));
|
||||
}
|
||||
|
||||
public static int getItemCustomEnchantsAmount(@NotNull ItemStack item) {
|
||||
return EnchantManager.getItemCustomEnchants(item).size();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Map<Enchantment, Integer> getItemEnchants(@NotNull ItemStack item) {
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
return (meta instanceof EnchantmentStorageMeta meta2) ? meta2.getStoredEnchants() : meta.getEnchants();
|
||||
}
|
||||
|
||||
public static int getItemEnchantsAmount(@NotNull ItemStack item) {
|
||||
return EnchantManager.getItemEnchants(item).size();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
public static void setArrowWeapon(@NotNull Projectile projectile, @NotNull ItemStack bow) {
|
||||
PROJECTILE_WEAPON.put(projectile.getUniqueId(), bow);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ItemStack getArrowWeapon(@NotNull Projectile projectile) {
|
||||
return PROJECTILE_WEAPON.get(projectile.getUniqueId());
|
||||
}
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
package su.nightexpress.excellentenchants.manager;
|
||||
|
||||
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 java.lang.reflect.Field;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class EnchantRegister {
|
||||
|
||||
private static final ExcellentEnchants PLUGIN;
|
||||
public static final Set<ExcellentEnchant> ENCHANT_LIST;
|
||||
|
||||
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 EnchantBaneOfNetherspawn BANE_OF_NETHERSPAWN;
|
||||
public static final EnchantIceAspect ICE_ASPECT;
|
||||
public static final EnchantInfernus INFERNUS;
|
||||
public static final EnchantVenom VENOM;
|
||||
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 EnchantConfusion CONFUSION;
|
||||
public static final EnchantDoubleStrike DOUBLE_STRIKE;
|
||||
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 EnchantThrifty THRIFTY;
|
||||
public static final EnchantThunder THUNDER;
|
||||
public static final EnchantVillageDefender VILLAGE_DEFENDER;
|
||||
public static final EnchantRocket ROCKET;
|
||||
|
||||
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 EnchantBomber BOMBER;
|
||||
public static final EnchantEnderBow ENDER_BOW;
|
||||
public static final EnchantGhast GHAST;
|
||||
public static final EnchantPoisonedArrows POISONED_ARROWS;
|
||||
public static final EnchantWitheredArrows WITHERED_ARROWS;
|
||||
public static final EnchantExplosiveArrows EXPLOSIVE_ARROWS;
|
||||
|
||||
static {
|
||||
PLUGIN = ExcellentEnchants.getInstance();
|
||||
PLUGIN.getConfigManager().extract("enchants");
|
||||
ENCHANT_LIST = new HashSet<>();
|
||||
|
||||
// Tool enchants
|
||||
BLAST_MINING = init(EnchantBlastMining.class, EnchantBlastMining.ID);
|
||||
CURSE_OF_BREAKING = init(EnchantCurseOfBreaking.class, EnchantCurseOfBreaking.ID);
|
||||
CURSE_OF_MISFORTUNE = init(EnchantCurseOfMisfortune.class, EnchantCurseOfMisfortune.ID);
|
||||
DIVINE_TOUCH = init(EnchantDivineTouch.class, EnchantDivineTouch.ID);
|
||||
HASTE = init(EnchantHaste.class, EnchantHaste.ID);
|
||||
LUCKY_MINER = init(EnchantLuckyMiner.class, EnchantLuckyMiner.ID);
|
||||
REPLANTER = init(EnchantReplanter.class, EnchantReplanter.ID);
|
||||
SILK_CHEST = init(EnchantSilkChest.class, EnchantSilkChest.ID);
|
||||
SMELTER = init(EnchantSmelter.class, EnchantSmelter.ID);
|
||||
TELEKINESIS = init(EnchantTelekinesis.class, EnchantTelekinesis.ID);
|
||||
TREASURES = init(EnchantTreasures.class, EnchantTreasures.ID);
|
||||
TUNNEL = init(EnchantTunnel.class, EnchantTunnel.ID);
|
||||
VEINMINER = init(EnchantVeinminer.class, EnchantVeinminer.ID);
|
||||
|
||||
// Weapon enchants
|
||||
BANE_OF_NETHERSPAWN = init(EnchantBaneOfNetherspawn.class, EnchantBaneOfNetherspawn.ID);
|
||||
BLINDNESS = init(EnchantBlindness.class, EnchantBlindness.ID);
|
||||
CONFUSION = init(EnchantConfusion.class, EnchantConfusion.ID);
|
||||
CUTTER = init(EnchantCutter.class, EnchantCutter.ID);
|
||||
DECAPITATOR = init(EnchantDecapitator.class, EnchantDecapitator.ID);
|
||||
DOUBLE_STRIKE = init(EnchantDoubleStrike.class, EnchantDoubleStrike.ID);
|
||||
EXHAUST = init(EnchantExhaust.class, EnchantExhaust.ID);
|
||||
EXP_HUNTER = init(EnchantExpHunter.class, EnchantExpHunter.ID);
|
||||
ICE_ASPECT = init(EnchantIceAspect.class, EnchantIceAspect.ID);
|
||||
INFERNUS = init(EnchantInfernus.class, EnchantInfernus.ID);
|
||||
NIMBLE = init(EnchantNimble.class, EnchantNimble.ID);
|
||||
PARALYZE = init(EnchantParalyze.class, EnchantParalyze.ID);
|
||||
CURE = init(EnchantCure.class, EnchantCure.ID);
|
||||
RAGE = init(EnchantRage.class, EnchantRage.ID);
|
||||
ROCKET = init(EnchantRocket.class, EnchantRocket.ID);
|
||||
SCAVENGER = init(EnchantScavenger.class, EnchantScavenger.ID);
|
||||
SURPRISE = init(EnchantSurprise.class, EnchantSurprise.ID);
|
||||
THRIFTY = init(EnchantThrifty.class, EnchantThrifty.ID);
|
||||
THUNDER = init(EnchantThunder.class, EnchantThunder.ID);
|
||||
VAMPIRE = init(EnchantVampire.class, EnchantVampire.ID);
|
||||
VENOM = init(EnchantVenom.class, EnchantVenom.ID);
|
||||
VILLAGE_DEFENDER = init(EnchantVillageDefender.class, EnchantVillageDefender.ID);
|
||||
WITHER = init(EnchantWither.class, EnchantWither.ID);
|
||||
|
||||
// Armor enchants
|
||||
AQUAMAN = init(EnchantAquaman.class, EnchantAquaman.ID);
|
||||
BUNNY_HOP = init(EnchantBunnyHop.class, EnchantBunnyHop.ID);
|
||||
COLD_STEEL = init(EnchantColdSteel.class, EnchantColdSteel.ID);
|
||||
FLAME_WALKER = init(EnchantFlameWalker.class, EnchantFlameWalker.ID);
|
||||
HARDENED = init(EnchantHardened.class, EnchantHardened.ID);
|
||||
NIGHT_VISION = init(EnchantNightVision.class, EnchantNightVision.ID);
|
||||
REGROWTH = init(EnchantRegrowth.class, EnchantRegrowth.ID);
|
||||
SATURATION = init(EnchantSaturation.class, EnchantSaturation.ID);
|
||||
SELF_DESTRUCTION = init(EnchantSelfDestruction.class, EnchantSelfDestruction.ID);
|
||||
SONIC = init(EnchantSonic.class, EnchantSonic.ID);
|
||||
|
||||
// Bow enchants
|
||||
BOMBER = init(EnchantBomber.class, EnchantBomber.ID);
|
||||
ENDER_BOW = init(EnchantEnderBow.class, EnchantEnderBow.ID);
|
||||
EXPLOSIVE_ARROWS = init(EnchantExplosiveArrows.class, EnchantExplosiveArrows.ID);
|
||||
GHAST = init(EnchantGhast.class, EnchantGhast.ID);
|
||||
POISONED_ARROWS = init(EnchantPoisonedArrows.class, EnchantPoisonedArrows.ID);
|
||||
WITHERED_ARROWS = init(EnchantWitheredArrows.class, EnchantWitheredArrows.ID);
|
||||
|
||||
}
|
||||
|
||||
public static void setup() {
|
||||
if (ExcellentEnchants.isLoaded) return; // Prevent to register enchantments during the runtime.
|
||||
|
||||
//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);
|
||||
EnchantRegister.register(enchant);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Enchantment.stopAcceptingRegistrations();
|
||||
PLUGIN.info("Enchants Registered: " + ENCHANT_LIST.size());
|
||||
ExcellentEnchants.isLoaded = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void shutdown() {
|
||||
if (PLUGIN.isEnabled()) return; // Prevent to unregister enchantments during the runtime.
|
||||
|
||||
Map<NamespacedKey, Enchantment> byKey = (Map<NamespacedKey, Enchantment>) Reflex.getFieldValue(Enchantment.class, "byKey");
|
||||
Map<String, Enchantment> byName = (Map<String, Enchantment>) Reflex.getFieldValue(Enchantment.class, "byName");
|
||||
|
||||
if (byKey == null || byName == null) return;
|
||||
|
||||
for (ExcellentEnchant enchant : ENCHANT_LIST) {
|
||||
if (enchant instanceof ICleanable cleanable) {
|
||||
cleanable.clear();
|
||||
}
|
||||
|
||||
byKey.remove(enchant.getKey());
|
||||
byName.remove(enchant.getName());
|
||||
enchant.unregisterListeners();
|
||||
}
|
||||
ENCHANT_LIST.clear();
|
||||
PLUGIN.info("All enchants are unregistered.");
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
JYML enchantCfg = JYML.loadOrExtract(PLUGIN, "/enchants/" + enchantId + ".yml");
|
||||
try {
|
||||
return clazz.getConstructor(ExcellentEnchants.class, JYML.class).newInstance(PLUGIN, enchantCfg);
|
||||
}
|
||||
catch (ReflectiveOperationException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void register(@Nullable ExcellentEnchant enchant) {
|
||||
if (enchant == null) return;
|
||||
|
||||
Enchantment.registerEnchantment(enchant);
|
||||
ENCHANT_LIST.add(enchant);
|
||||
enchant.registerListeners();
|
||||
PLUGIN.info("Registered enchantment: " + enchant.getId());
|
||||
//IRegistry.a(IRegistry.ENCHANTMENT, enchant.getId(), CraftEnchantment.getRaw(enchant));
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
|
||||
public class EnchantAquaman extends IEnchantPotionTemplate implements PassiveEnchant {
|
||||
|
||||
public static final String ID = "aquaman";
|
||||
|
||||
public EnchantAquaman(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.WATER_BREATHING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_HEAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull LivingEntity entity, int level) {
|
||||
if (!this.isEnchantmentAvailable(entity)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(entity)) return false;
|
||||
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
|
||||
public class EnchantBunnyHop extends IEnchantPotionTemplate implements PassiveEnchant {
|
||||
|
||||
public static final String ID = "bunny_hop";
|
||||
|
||||
public EnchantBunnyHop(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.JUMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_FEET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull LivingEntity entity, int level) {
|
||||
if (!this.isEnchantmentAvailable(entity)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(entity)) return false;
|
||||
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.nexmedia.engine.api.config.JYML;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
|
||||
public class EnchantColdSteel extends IEnchantPotionTemplate implements CombatEnchant {
|
||||
|
||||
public static final String ID = "cold_steel";
|
||||
|
||||
public EnchantColdSteel(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.SLOW_DIGGING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
@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(victim)) return false;
|
||||
|
||||
return this.addEffect(damager, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.armor;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
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.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
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.type.MoveEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class EnchantFlameWalker extends IEnchantChanceTemplate implements MoveEnchant, 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 final Scaler blockDecayTime;
|
||||
private BlockTickTask blockTickTask;
|
||||
|
||||
public EnchantFlameWalker(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
this.blockDecayTime = new EnchantScaler(this, "Settings.Block_Decay");
|
||||
|
||||
this.blockTickTask = new BlockTickTask(plugin);
|
||||
this.blockTickTask.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.addMissing("Settings.Block_Decay", "5.0 + " + PLACEHOLDER_LEVEL + " * 2");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (this.blockTickTask != null) {
|
||||
this.blockTickTask.stop();
|
||||
this.blockTickTask = null;
|
||||
}
|
||||
BLOCKS_TO_DESTROY.keySet().forEach(block -> block.setType(Material.LAVA));
|
||||
BLOCKS_TO_DESTROY.clear();
|
||||
}
|
||||
|
||||
public static void addBlock(@NotNull Block block, double seconds) {
|
||||
BLOCKS_TO_DESTROY.put(block, (long) (System.currentTimeMillis() + seconds * 1000L));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(Enchantment.FROST_WALKER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_FEET;
|
||||
}
|
||||
|
||||
public double getBlockDecayTime(int level) {
|
||||
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) {
|
||||
Player player = e.getPlayer();
|
||||
if (player.isFlying()) return;
|
||||
if (!this.isEnchantmentAvailable(player)) return;
|
||||
|
||||
Location from = e.getFrom();
|
||||
Location to = e.getTo();
|
||||
if (to == null) return;
|
||||
if (from.getX() == to.getX() && from.getY() == to.getY() && from.getZ() == to.getZ()) return;
|
||||
|
||||
ItemStack boots = player.getInventory().getBoots();
|
||||
if (boots == null || boots.getType().isAir()) return;
|
||||
|
||||
int level = boots.getEnchantmentLevel(this);
|
||||
if (level < 1) 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);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onFlameWalkerBlock(BlockBreakEvent e) {
|
||||
if (BLOCKS_TO_DESTROY.containsKey(e.getBlock())) {
|
||||
e.setDropItems(false);
|
||||
e.setExpToDrop(0);
|
||||
e.getBlock().setType(Material.LAVA);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onFlameWalkerMagmaDamage(EntityDamageEvent e) {
|
||||
if (e.getCause() != EntityDamageEvent.DamageCause.HOT_FLOOR) return;
|
||||
if (!(e.getEntity() instanceof LivingEntity livingEntity)) return;
|
||||
if (!this.isEnchantmentAvailable(livingEntity)) return;
|
||||
|
||||
EntityEquipment equipment = livingEntity.getEquipment();
|
||||
if (equipment == null) return;
|
||||
|
||||
ItemStack boots = equipment.getBoots();
|
||||
if (boots == null || boots.getType().isAir()) return;
|
||||
|
||||
int level = boots.getEnchantmentLevel(this);
|
||||
if (level < 1) return;
|
||||
if (!this.checkTriggerChance(level)) return;
|
||||
|
||||
e.setCancelled(true);
|
||||
}
|
||||
|
||||
static class BlockTickTask extends AbstractTask<ExcellentEnchants> {
|
||||
|
||||
public BlockTickTask(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, 1, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action() {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
BLOCKS_TO_DESTROY.keySet().removeIf(block -> {
|
||||
if (block.isEmpty()) return true;
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.nexmedia.engine.api.config.JYML;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
|
||||
public class EnchantHardened extends IEnchantPotionTemplate implements CombatEnchant {
|
||||
|
||||
public static final String ID = "hardened";
|
||||
|
||||
public EnchantHardened(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.DAMAGE_RESISTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
@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(victim)) return false;
|
||||
|
||||
return this.addEffect(victim, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
|
||||
public class EnchantNightVision extends IEnchantPotionTemplate implements PassiveEnchant {
|
||||
|
||||
public static final String ID = "night_vision";
|
||||
|
||||
public EnchantNightVision(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.NIGHT_VISION);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_HEAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull LivingEntity entity, int level) {
|
||||
if (!this.isEnchantmentAvailable(entity)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(entity)) return false;
|
||||
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.api.manager.ICleanable;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.manager.tasks.AbstractEnchantPassiveTask;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantRegrowth extends IEnchantChanceTemplate implements PassiveEnchant, ICleanable {
|
||||
|
||||
public static final String ID = "regrowth";
|
||||
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
private final long healthInterval;
|
||||
private final Scaler healthAmount;
|
||||
private Task healthTask;
|
||||
|
||||
private static final String PLACEHOLDER_HEALTH_AMOUNT = "%enchantment_health_amount%";
|
||||
private static final String PLACEHOLDER_HEALTH_INTERVAL = "%enchantment_health_interval%";
|
||||
|
||||
public EnchantRegrowth(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
this.particleName = cfg.getString("Settings.Particle.Name", Particle.HEART.name());
|
||||
this.particleData = cfg.getString("Settings.Particle.Data", "");
|
||||
this.healthInterval = cfg.getLong("Settings.Health.Interval", 100);
|
||||
this.healthAmount = new EnchantScaler(this, "Settings.Health.Amount");
|
||||
this.healthTask = new Task(plugin);
|
||||
this.healthTask.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.addMissing("Settings.Health.Interval", 100);
|
||||
cfg.addMissing("Settings.Particle.Name", Particle.HEART.name());
|
||||
cfg.addMissing("Settings.Particle.Data", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (this.healthTask != null) {
|
||||
this.healthTask.stop();
|
||||
this.healthTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return str -> super.replacePlaceholders(level).apply(str
|
||||
.replace(PLACEHOLDER_HEALTH_AMOUNT, NumberUtil.format(this.getHealthAmount(level)))
|
||||
.replace(PLACEHOLDER_HEALTH_INTERVAL, NumberUtil.format((double) this.healthInterval / 20D))
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
public double getHealthAmount(int level) {
|
||||
return this.healthAmount.getValue(level);
|
||||
}
|
||||
|
||||
public long getHealthInterval() {
|
||||
return this.healthInterval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull LivingEntity entity, int level) {
|
||||
if (!this.isEnchantmentAvailable(entity)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
double healthMax = EntityUtil.getAttribute(entity, Attribute.GENERIC_MAX_HEALTH);
|
||||
double healthHas = entity.getHealth();
|
||||
if (healthHas >= healthMax) return false;
|
||||
if (!this.takeCostItem(entity)) return false;
|
||||
|
||||
double amount = Math.min(healthMax, healthHas + this.getHealthAmount(level));
|
||||
|
||||
entity.setHealth(amount);
|
||||
EffectUtil.playEffect(entity.getEyeLocation(), this.particleName, this.particleData, 0.3, 0.3, 0.3, 0.1, 15);
|
||||
return true;
|
||||
}
|
||||
|
||||
class Task extends AbstractEnchantPassiveTask {
|
||||
|
||||
public Task(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, healthInterval, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(@NotNull LivingEntity entity, @NotNull ItemStack armor, @NotNull ItemMeta meta) {
|
||||
int level = meta.getEnchantLevel(EnchantRegrowth.this);
|
||||
if (level < 1) return;
|
||||
|
||||
use(entity, level);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.api.manager.ICleanable;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
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.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.manager.tasks.AbstractEnchantPassiveTask;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantSaturation extends IEnchantChanceTemplate implements PassiveEnchant, ICleanable {
|
||||
|
||||
private final long saturationInterval;
|
||||
private final Scaler saturationAmount;
|
||||
private Task saturationTask;
|
||||
|
||||
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%";
|
||||
|
||||
public EnchantSaturation(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
this.saturationInterval = cfg.getLong("Settings.Saturation.Interval", 100);
|
||||
this.saturationAmount = new EnchantScaler(this, "Settings.Saturation.Amount");
|
||||
this.saturationTask = new Task(plugin);
|
||||
this.saturationTask.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.addMissing("Settings.Saturation.Interval", 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (this.saturationTask != null) {
|
||||
this.saturationTask.stop();
|
||||
this.saturationTask = 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))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
public final double getSaturationAmount(int level) {
|
||||
return this.saturationAmount.getValue(level);
|
||||
}
|
||||
|
||||
public long getSaturationInterval() {
|
||||
return saturationInterval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull LivingEntity entity, int level) {
|
||||
if (!this.isEnchantmentAvailable(entity)) return false;
|
||||
if (!(entity instanceof Player player)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (player.getFoodLevel() >= 20) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
float amount = (float) this.getSaturationAmount(level);
|
||||
player.setFoodLevel((int) Math.min(20, player.getFoodLevel() + amount));
|
||||
player.setSaturation(Math.min(20, player.getSaturation() + amount));
|
||||
return true;
|
||||
}
|
||||
|
||||
class Task extends AbstractEnchantPassiveTask {
|
||||
|
||||
public Task(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, saturationInterval, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(@NotNull LivingEntity entity, @NotNull ItemStack armor, @NotNull ItemMeta meta) {
|
||||
int level = meta.getEnchantLevel(EnchantSaturation.this);
|
||||
if (level < 1) return;
|
||||
|
||||
use(entity, level);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.manager.leveling.Scaler;
|
||||
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.api.enchantment.type.DeathEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantSelfDestruction extends IEnchantChanceTemplate implements DeathEnchant {
|
||||
|
||||
private final Scaler explosionSize;
|
||||
|
||||
public static final String ID = "self_destruction";
|
||||
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);
|
||||
this.explosionSize = new EnchantScaler(this, "Settings.Explosion.Size");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return str -> super.replacePlaceholders(level).apply(str
|
||||
.replace(PLACEHOLDER_EXPLOSION_POWER, NumberUtil.format(this.getExplosionSize(level)))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
public final double getExplosionSize(int level) {
|
||||
return this.explosionSize.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level) {
|
||||
if (!this.isEnchantmentAvailable(dead)) 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);
|
||||
return exploded;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onItemDamage(EntityDamageByEntityEvent e) {
|
||||
if (!e.getDamager().hasMetadata(META_EXPLOSION_SOURCE)) return;
|
||||
if (!(e.getEntity() instanceof Item item)) return;
|
||||
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
|
||||
public class EnchantSonic extends IEnchantPotionTemplate implements PassiveEnchant {
|
||||
|
||||
public static final String ID = "sonic";
|
||||
|
||||
public EnchantSonic(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.SPEED);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.ARMOR_FEET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull LivingEntity entity, int level) {
|
||||
if (!this.isEnchantmentAvailable(entity)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(entity)) return false;
|
||||
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.bow;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.TNTPrimed;
|
||||
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.api.config.JYML;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
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.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantBomber extends IEnchantChanceTemplate implements BowEnchant {
|
||||
|
||||
private final Scaler fuseTicks;
|
||||
|
||||
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);
|
||||
|
||||
this.fuseTicks = new EnchantScaler(this, "Settings.Fuse_Ticks");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
this.cfg.addMissing("Settings.Fuse_Ticks", "100 - %enchantment_level% * 10");
|
||||
}
|
||||
|
||||
@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))
|
||||
);
|
||||
}
|
||||
|
||||
public int getFuseTicks(int level) {
|
||||
return (int) this.fuseTicks.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.ENDER_BOW);
|
||||
this.addConflict(EnchantRegister.GHAST);
|
||||
this.addConflict(EnchantRegister.EXPLOSIVE_ARROWS);
|
||||
this.addConflict(EnchantRegister.WITHERED_ARROWS);
|
||||
this.addConflict(EnchantRegister.POISONED_ARROWS);
|
||||
this.addConflict(Enchantment.ARROW_FIRE);
|
||||
this.addConflict(Enchantment.ARROW_DAMAGE);
|
||||
this.addConflict(Enchantment.ARROW_KNOCKBACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@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;
|
||||
if (!(e.getProjectile() instanceof Projectile projectile)) return false;
|
||||
if (!bow.containsEnchantment(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));
|
||||
primed.setFuseTicks(this.getFuseTicks(level));
|
||||
primed.setSource(shooter);
|
||||
e.setProjectile(primed);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@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) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.bow;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
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.nexmedia.engine.api.config.JYML;
|
||||
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.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
|
||||
public class EnchantEnderBow extends IEnchantChanceTemplate implements BowEnchant {
|
||||
|
||||
public static final String ID = "ender_bow";
|
||||
|
||||
public EnchantEnderBow(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.HIGHEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.BOMBER);
|
||||
this.addConflict(EnchantRegister.GHAST);
|
||||
this.addConflict(EnchantRegister.EXPLOSIVE_ARROWS);
|
||||
this.addConflict(EnchantRegister.WITHERED_ARROWS);
|
||||
this.addConflict(EnchantRegister.POISONED_ARROWS);
|
||||
this.addConflict(Enchantment.ARROW_FIRE);
|
||||
this.addConflict(Enchantment.ARROW_DAMAGE);
|
||||
this.addConflict(Enchantment.ARROW_KNOCKBACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@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;
|
||||
if (!(e.getProjectile() instanceof Projectile projectile)) return false;
|
||||
if (!bow.containsEnchantment(ARROW_INFINITE) && !this.takeCostItem(shooter)) return false;
|
||||
|
||||
EnderPearl pearl = shooter.launchProjectile(EnderPearl.class);
|
||||
pearl.setVelocity(projectile.getVelocity());
|
||||
e.setProjectile(pearl);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@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) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.bow;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Item;
|
||||
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.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.nexmedia.engine.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantBowTemplate;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantExplosiveArrows extends IEnchantBowTemplate {
|
||||
|
||||
private final boolean explosionFireSpread;
|
||||
private final boolean explosionDamageItems;
|
||||
private final boolean explosionDamageBlocks;
|
||||
private final Scaler explosionSize;
|
||||
|
||||
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";
|
||||
|
||||
public EnchantExplosiveArrows(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
this.explosionFireSpread = cfg.getBoolean("Settings.Explosion.Fire_Spread");
|
||||
this.explosionDamageItems = cfg.getBoolean("Settings.Explosion.Damage_Items");
|
||||
this.explosionDamageBlocks = cfg.getBoolean("Settings.Explosion.Damage_Blocks");
|
||||
this.explosionSize = new EnchantScaler(this, "Settings.Explosion.Size");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
this.cfg.addMissing("Settings.Explosion.Fire_Spread", true);
|
||||
this.cfg.addMissing("Settings.Explosion.Damage_Items", true);
|
||||
this.cfg.addMissing("Settings.Explosion.Damage_Blocks", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return str -> super.replacePlaceholders(level).apply(str
|
||||
.replace(PLACEHOLDER_EXPLOSION_POWER, NumberUtil.format(this.getExplosionSize(level)))
|
||||
);
|
||||
}
|
||||
|
||||
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 use(@NotNull ProjectileHitEvent e, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
if (!super.use(e, projectile, bow, level)) 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;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.bow;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Fireball;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.SmallFireball;
|
||||
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.api.config.JYML;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
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.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
public class EnchantGhast extends IEnchantChanceTemplate implements BowEnchant {
|
||||
|
||||
private final boolean fireSpread;
|
||||
private final Scaler yield;
|
||||
|
||||
public static final String ID = "ghast";
|
||||
|
||||
public EnchantGhast(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.HIGHEST);
|
||||
|
||||
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 * " + PLACEHOLDER_LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.BOMBER);
|
||||
this.addConflict(EnchantRegister.ENDER_BOW);
|
||||
this.addConflict(EnchantRegister.EXPLOSIVE_ARROWS);
|
||||
this.addConflict(EnchantRegister.WITHERED_ARROWS);
|
||||
this.addConflict(EnchantRegister.POISONED_ARROWS);
|
||||
this.addConflict(Enchantment.ARROW_FIRE);
|
||||
this.addConflict(Enchantment.ARROW_KNOCKBACK);
|
||||
}
|
||||
|
||||
public boolean isFireSpread() {
|
||||
return fireSpread;
|
||||
}
|
||||
|
||||
public float getYield(int level) {
|
||||
return (float) this.yield.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@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;
|
||||
if (!(e.getProjectile() instanceof Projectile projectile)) return false;
|
||||
if (!bow.containsEnchantment(ARROW_INFINITE) && !this.takeCostItem(shooter)) return false;
|
||||
|
||||
Fireball fireball;
|
||||
|
||||
// Shoot small fireballs for the Multishot enchantment,
|
||||
// as large ones has a slow speed and punches each other on shoot.
|
||||
if (bow.containsEnchantment(Enchantment.MULTISHOT)) {
|
||||
fireball = shooter.launchProjectile(SmallFireball.class);
|
||||
fireball.setVelocity(projectile.getVelocity().normalize().multiply(0.5f));
|
||||
}
|
||||
else {
|
||||
fireball = shooter.launchProjectile(Fireball.class);
|
||||
fireball.setDirection(projectile.getVelocity());
|
||||
}
|
||||
fireball.setIsIncendiary(this.isFireSpread());
|
||||
fireball.setYield(this.getYield(level));
|
||||
|
||||
e.setProjectile(fireball);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@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 = weapon.getEnchantmentLevel(Enchantment.ARROW_DAMAGE);
|
||||
if (power < 1) return false;
|
||||
|
||||
double damagePower = 0.5 + power * 0.5;
|
||||
e.setDamage(e.getDamage() + damagePower);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.bow;
|
||||
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantBowPotionTemplate;
|
||||
|
||||
public class EnchantPoisonedArrows extends IEnchantBowPotionTemplate {
|
||||
|
||||
public static final String ID = "poisoned_arrows";
|
||||
|
||||
public EnchantPoisonedArrows(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.POISON);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.bow;
|
||||
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantBowPotionTemplate;
|
||||
|
||||
public class EnchantWitheredArrows extends IEnchantBowPotionTemplate {
|
||||
|
||||
public static final String ID = "withered_arrows";
|
||||
|
||||
public EnchantWitheredArrows(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.WITHER);
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
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.manager.leveling.Scaler;
|
||||
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.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.hook.HookNCP;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantBlastMining extends IEnchantChanceTemplate implements BlockBreakEnchant {
|
||||
|
||||
private final Scaler explosionPower;
|
||||
private final Scaler minBlockStrength;
|
||||
|
||||
public static final String ID = "blast_mining";
|
||||
public static final String PLACEHOLDER_EXPLOSION_POWER = "%enchantment_explosion_power%";
|
||||
|
||||
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);
|
||||
|
||||
this.explosionPower = new EnchantScaler(this, "Settings.Explosion.Power");
|
||||
this.minBlockStrength = new EnchantScaler(this, "Settings.Min_Block_Strength");
|
||||
}
|
||||
|
||||
public double getExplosionPower(int level) {
|
||||
return this.explosionPower.getValue(level);
|
||||
}
|
||||
|
||||
public float getMinBlockStrength(int level) {
|
||||
return (float) minBlockStrength.getValue(level);
|
||||
}
|
||||
|
||||
private boolean isBlockHardEnough(@NotNull Block block, int level) {
|
||||
float strength = plugin.getNMS().getBlockStrength(block);
|
||||
return (strength >= this.getMinBlockStrength(level));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.addMissing("Settings.Min_Block_Strength", "1.5 - " + PLACEHOLDER_LEVEL + " / 10.0");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.TUNNEL);
|
||||
this.addConflict(EnchantRegister.VEINMINER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return str -> super.replacePlaceholders(level).apply(str
|
||||
.replace(PLACEHOLDER_EXPLOSION_POWER, NumberUtil.format(this.getExplosionPower(level)))
|
||||
);
|
||||
}
|
||||
|
||||
/*@Override
|
||||
public boolean isFitItemType(@NotNull ItemStack item) {
|
||||
return ItemUtil.isPickaxe(item);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.PICKAXE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
|
||||
if (EnchantRegister.VEINMINER != null && item.containsEnchantment(EnchantRegister.VEINMINER)) return false;
|
||||
if (EnchantRegister.TUNNEL != null && item.containsEnchantment(EnchantRegister.TUNNEL)) return false;
|
||||
|
||||
Block block = e.getBlock();
|
||||
if (block.hasMetadata(META_EXPLOSION_MINED)) return false;
|
||||
|
||||
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);
|
||||
boolean exploded = block.getWorld().createExplosion(block.getLocation(), power, false, true, player);
|
||||
HookNCP.unexemptBlocks(player);
|
||||
player.removeMetadata(META_EXPLOSION_SOURCE, plugin);
|
||||
return exploded;
|
||||
}
|
||||
|
||||
// Process explosion event to mine blocks.
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onBlastExplosionEvent(EntityExplodeEvent e) {
|
||||
if (!(e.getEntity() instanceof Player player)) return;
|
||||
if (!player.hasMetadata(META_EXPLOSION_SOURCE)) return;
|
||||
|
||||
int level = player.getMetadata(META_EXPLOSION_SOURCE).get(0).asInt();
|
||||
List<Block> blockList = e.blockList();
|
||||
|
||||
// Remove the 'source' block which player mined and caused the explosion to prevent duplicated drops.
|
||||
// Remove all the 'soft' blocks that should not be exploded.
|
||||
blockList.removeIf(block -> block.getLocation().equals(e.getLocation()) || !this.isBlockHardEnough(block, level));
|
||||
|
||||
// Break all 'exploded' blocks by a player, adding metadata to them to prevent trigger enchantment in a loop.
|
||||
blockList.forEach(block -> {
|
||||
block.setMetadata(META_EXPLOSION_MINED, new FixedMetadataValue(plugin, true));
|
||||
plugin.getNMS().breakBlock(player, block);
|
||||
block.removeMetadata(META_EXPLOSION_MINED, plugin);
|
||||
});
|
||||
|
||||
// Clear list of 'exploded' blocks so the event won't affect them, as they are already mined by a player.
|
||||
blockList.clear();
|
||||
}
|
||||
|
||||
// Do not damage around entities by en enchantment explosion.
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onBlastExplosionDamage(EntityDamageByEntityEvent e) {
|
||||
if (e.getCause() != DamageCause.ENTITY_EXPLOSION) return;
|
||||
if (!(e.getDamager() instanceof Player player)) return;
|
||||
|
||||
e.setCancelled(player.hasMetadata(META_EXPLOSION_SOURCE));
|
||||
}
|
||||
|
||||
// Do not reduce item durability for 'exploded' blocks.
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onBlastExplosionItemDamage(PlayerItemDamageEvent e) {
|
||||
if (!e.getPlayer().hasMetadata(META_EXPLOSION_SOURCE)) return;
|
||||
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
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.manager.leveling.Scaler;
|
||||
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.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantCurseOfBreaking extends IEnchantChanceTemplate {
|
||||
|
||||
private final Scaler durabilityAmount;
|
||||
|
||||
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);
|
||||
|
||||
this.durabilityAmount = new EnchantScaler(this, "Settings.Durability_Amount");
|
||||
}
|
||||
|
||||
public int getDurabilityAmount(int level) {
|
||||
return (int) this.durabilityAmount.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(Enchantment.DURABILITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return str -> super.replacePlaceholders(level).apply(str
|
||||
.replace(PLACEHOLDER_DURABILITY_AMOUNT, NumberUtil.format(this.getDurabilityAmount(level)))
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.BREAKABLE;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onItemDurability(PlayerItemDamageEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
if (!this.isEnchantmentAvailable(player)) return;
|
||||
|
||||
ItemStack item = e.getItem();
|
||||
int level = item.getEnchantmentLevel(this);
|
||||
|
||||
if (level < 1) return;
|
||||
if (!this.checkTriggerChance(level)) return;
|
||||
if (!this.takeCostItem(player)) return;
|
||||
|
||||
int durabilityAmount = this.getDurabilityAmount(level);
|
||||
if (durabilityAmount <= 0) return;
|
||||
|
||||
e.setDamage(e.getDamage() + durabilityAmount);
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.JYML;
|
||||
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.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
public class EnchantCurseOfMisfortune extends IEnchantChanceTemplate implements BlockBreakEnchant, DeathEnchant {
|
||||
|
||||
private final boolean dropExp;
|
||||
|
||||
public static final String ID = "curse_of_misfortune";
|
||||
|
||||
public EnchantCurseOfMisfortune(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.LOW);
|
||||
|
||||
this.dropExp = cfg.getBoolean("Settings.Drop_Exp");
|
||||
}
|
||||
|
||||
public boolean isDropExp() {
|
||||
return dropExp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(LOOT_BONUS_BLOCKS);
|
||||
this.addConflict(LOOT_BONUS_MOBS);
|
||||
}
|
||||
|
||||
@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 use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (EnchantTelekinesis.isDropHandled(e.getBlock())) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
e.setDropItems(false);
|
||||
if (!this.isDropExp()) e.setExpToDrop(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level) {
|
||||
Player player = dead.getKiller();
|
||||
if (player == null) return false;
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
e.getDrops().clear();
|
||||
if (!this.isDropExp()) e.setDroppedExp(0);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CustomDropEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class EnchantDivineTouch extends IEnchantChanceTemplate implements BlockBreakEnchant, CustomDropEnchant {
|
||||
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
private final String spawnerName;
|
||||
|
||||
public static final String ID = "divine_touch";
|
||||
|
||||
public EnchantDivineTouch(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
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%)"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.SMELTER);
|
||||
}
|
||||
|
||||
@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", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.PICKAXE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getSpawner(@NotNull CreatureSpawner spawnerBlock) {
|
||||
ItemStack itemSpawner = new ItemStack(Material.SPAWNER);
|
||||
BlockStateMeta stateItem = (BlockStateMeta) itemSpawner.getItemMeta();
|
||||
if (stateItem == null) return itemSpawner;
|
||||
|
||||
CreatureSpawner spawnerItem = (CreatureSpawner) stateItem.getBlockState();
|
||||
spawnerItem.setSpawnedType(spawnerBlock.getSpawnedType());
|
||||
spawnerItem.update(true);
|
||||
stateItem.setBlockState(spawnerItem);
|
||||
stateItem.setDisplayName(this.spawnerName.replace("%type%", plugin.lang().getEnum(spawnerBlock.getSpawnedType())));
|
||||
itemSpawner.setItemMeta(stateItem);
|
||||
|
||||
return itemSpawner;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<ItemStack> getCustomDrops(@NotNull Player player, @NotNull ItemStack item, @NotNull Block block, int level) {
|
||||
if (!(block.getState() instanceof CreatureSpawner spawnerBlock)) return Collections.emptyList();
|
||||
|
||||
return Collections.singletonList(this.getSpawner(spawnerBlock));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEventMustHaveDrops() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
Block block = e.getBlock();
|
||||
if (EnchantTelekinesis.isDropHandled(block)) return false;
|
||||
if (!(block.getState() instanceof CreatureSpawner spawnerBlock)) return false;
|
||||
if (this.isEventMustHaveDrops() && !e.isDropItems()) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
Location location = LocationUtil.getCenter(block.getLocation());
|
||||
World world = block.getWorld();
|
||||
|
||||
this.getCustomDrops(player, item, block, level).forEach(itemSpawner -> world.dropItemNaturally(location, itemSpawner));
|
||||
EffectUtil.playEffect(location, this.particleName, this.particleData, 0.3f, 0.3f, 0.3f, 0.15f, 30);
|
||||
|
||||
e.setExpToDrop(0);
|
||||
e.setDropItems(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update spawner type of the placed spawner mined by Divine Touch.
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onSpawnerPlace(BlockPlaceEvent e) {
|
||||
Block block = e.getBlock();
|
||||
if (block.getType() != Material.SPAWNER) return;
|
||||
|
||||
Player player = e.getPlayer();
|
||||
ItemStack spawner = player.getInventory().getItemInMainHand();
|
||||
if (spawner.getType().isAir() || spawner.getType() != Material.SPAWNER) {
|
||||
spawner = player.getInventory().getItemInOffHand();
|
||||
}
|
||||
if (spawner.getType().isAir() || spawner.getType() != Material.SPAWNER) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockStateMeta meta = (BlockStateMeta) spawner.getItemMeta();
|
||||
if (meta == null) return;
|
||||
|
||||
CreatureSpawner spawnerItem = (CreatureSpawner) meta.getBlockState();
|
||||
CreatureSpawner spawnerBlock = (CreatureSpawner) block.getState();
|
||||
|
||||
spawnerBlock.setSpawnedType(spawnerItem.getSpawnedType());
|
||||
spawnerBlock.update();
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
|
||||
public class EnchantHaste extends IEnchantPotionTemplate implements PassiveEnchant {
|
||||
|
||||
public static final String ID = "haste";
|
||||
|
||||
public EnchantHaste(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.FAST_DIGGING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull LivingEntity entity, int level) {
|
||||
if (!this.isEnchantmentAvailable(entity)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(entity)) return false;
|
||||
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.manager.leveling.Scaler;
|
||||
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.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantLuckyMiner extends IEnchantChanceTemplate implements BlockBreakEnchant {
|
||||
|
||||
private final Scaler expModifier;
|
||||
|
||||
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);
|
||||
this.expModifier = new EnchantScaler(this, "Settings.Exp_Modifier");
|
||||
}
|
||||
|
||||
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
|
||||
.replace(PLACEHOLDER_EXP_MODIFIER, NumberUtil.format(this.getExpModifier(level) * 100D - 100D))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.PICKAXE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@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;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
double expMod = this.getExpModifier(level);
|
||||
e.setExpToDrop((int) ((double) e.getExpToDrop() * expMod));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.Ageable;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
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.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.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.InteractEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class EnchantReplanter extends IEnchantChanceTemplate implements InteractEnchant, BlockBreakEnchant {
|
||||
|
||||
private final boolean replantOnRightClick;
|
||||
private final 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,
|
||||
Material.POTATO, Material.CARROT, Material.NETHER_WART);
|
||||
|
||||
public EnchantReplanter(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.HIGH);
|
||||
|
||||
this.replantOnRightClick = cfg.getBoolean("Settings.Replant.On_Right_Click");
|
||||
this.replantOnPlantBreak = cfg.getBoolean("Settings.Replant.On_Plant_Break");
|
||||
}
|
||||
|
||||
public boolean isReplantOnPlantBreak() {
|
||||
return replantOnPlantBreak;
|
||||
}
|
||||
|
||||
public boolean isReplantOnRightClick() {
|
||||
return replantOnRightClick;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Material fineSeedsToBlock(@NotNull Material material) {
|
||||
if (material == Material.POTATO) return Material.POTATOES;
|
||||
if (material == Material.CARROT) return Material.CARROTS;
|
||||
if (material == Material.BEETROOT_SEEDS) return Material.BEETROOTS;
|
||||
if (material == Material.WHEAT_SEEDS) return Material.WHEAT;
|
||||
if (material == Material.PUMPKIN_SEEDS) return Material.PUMPKIN_STEM;
|
||||
if (material == Material.MELON_SEEDS) return Material.MELON_STEM;
|
||||
return material;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Material fineBlockToSeeds(@NotNull Material material) {
|
||||
if (material == Material.POTATOES) return Material.POTATO;
|
||||
if (material == Material.CARROTS) return Material.CARROT;
|
||||
if (material == Material.BEETROOTS) return Material.BEETROOT_SEEDS;
|
||||
if (material == Material.WHEAT) return Material.WHEAT_SEEDS;
|
||||
if (material == Material.MELON_STEM) return Material.MELON_SEEDS;
|
||||
if (material == Material.PUMPKIN_STEM) return Material.PUMPKIN_SEEDS;
|
||||
return material;
|
||||
}
|
||||
|
||||
private boolean takeSeeds(@NotNull Player player, @NotNull Material material) {
|
||||
material = this.fineBlockToSeeds(material);
|
||||
|
||||
int slot = player.getInventory().first(material);
|
||||
if (slot < 0) return false;
|
||||
|
||||
ItemStack seed = player.getInventory().getItem(slot);
|
||||
if (seed == null || seed.getType().isAir()) return false;
|
||||
|
||||
seed.setAmount(seed.getAmount() - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.HOE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull PlayerInteractEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (!this.isReplantOnRightClick()) return false;
|
||||
|
||||
// Check for a event hand. We dont want to trigger it twice.
|
||||
if (e.getHand() != EquipmentSlot.HAND) return false;
|
||||
if (e.getAction() != Action.RIGHT_CLICK_BLOCK) return false;
|
||||
|
||||
// Check if player holds seeds to plant them by offhand interaction.
|
||||
ItemStack off = player.getInventory().getItemInOffHand();
|
||||
if (!off.getType().isAir() && CROPS.contains(off.getType())) return false;
|
||||
|
||||
// Check if clicked block is a farmland.
|
||||
Block blockGround = e.getClickedBlock();
|
||||
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;
|
||||
|
||||
// Get the first crops from player's inventory and plant them.
|
||||
for (Material seed : CROPS) {
|
||||
if (seed == Material.NETHER_WART && blockGround.getType() == Material.SOUL_SAND
|
||||
|| seed != Material.NETHER_WART && blockGround.getType() == Material.FARMLAND) {
|
||||
if (this.takeSeeds(player, seed)) {
|
||||
MessageUtil.sound(player, seed == Material.NETHER_WART ? Sound.ITEM_NETHER_WART_PLANT : Sound.ITEM_CROP_PLANT);
|
||||
plugin.getNMS().sendAttackPacket(player, 0);
|
||||
blockPlant.setType(this.fineSeedsToBlock(seed));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (!this.isReplantOnPlantBreak()) return false;
|
||||
|
||||
Block blockPlant = e.getBlock();
|
||||
//if (EnchantTelekinesis.isDropHandled(blockPlant)) return false;
|
||||
//if (EnchantRegister.TELEKINESIS != null && item.containsEnchantment(EnchantRegister.TELEKINESIS)) return false;
|
||||
|
||||
// Check if broken block is supported crop(s).
|
||||
if (!CROPS.contains(this.fineBlockToSeeds(blockPlant.getType()))) return false;
|
||||
|
||||
// Check if broken block is actually can grow.
|
||||
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);
|
||||
return false;
|
||||
}*/
|
||||
|
||||
// Replant the gathered crops with a new one.
|
||||
if (this.takeSeeds(player, plant.getMaterial())) {
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
blockPlant.setType(plant.getMaterial());
|
||||
plant.setAge(0);
|
||||
blockPlant.setBlockData(plant);
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Chest;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
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.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CustomDropEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class EnchantSilkChest extends IEnchantChanceTemplate implements BlockBreakEnchant, CustomDropEnchant {
|
||||
|
||||
private final Map<Integer, NamespacedKey> keyItems;
|
||||
private final String chestName;
|
||||
|
||||
public static final String ID = "silk_chest";
|
||||
|
||||
public EnchantSilkChest(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
this.keyItems = new TreeMap<>();
|
||||
this.chestName = StringUtil.color(cfg.getString("Settings.Chest_Item.Name", "%name% &7(%items% items)"));
|
||||
|
||||
for (int pos = 0; pos < 27; pos++) {
|
||||
this.getItemKey(pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.AXE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
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;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getSilkChest(@NotNull Chest chest) {
|
||||
Block block = chest.getBlock();
|
||||
ItemStack chestItem = new ItemStack(block.getType());
|
||||
|
||||
// Store and count chest items.
|
||||
int amount = 0;
|
||||
int count = 0;
|
||||
for (ItemStack itemInv : chest.getBlockInventory().getContents()) {
|
||||
if (itemInv == null) itemInv = new ItemStack(Material.AIR);
|
||||
else amount++;
|
||||
|
||||
String base64 = ItemUtil.toBase64(itemInv);
|
||||
if (base64 == null) continue;
|
||||
if (base64.length() >= Short.MAX_VALUE) {
|
||||
block.getWorld().dropItemNaturally(block.getLocation(), itemInv);
|
||||
continue;
|
||||
}
|
||||
PDCUtil.setData(chestItem, this.getItemKey(count++), base64);
|
||||
}
|
||||
|
||||
// Apply item meta name and items data string.
|
||||
ItemMeta meta = chestItem.getItemMeta();
|
||||
if (meta != null) {
|
||||
String nameOrig = ItemUtil.getItemName(chestItem);
|
||||
String nameChest = this.chestName.replace("%name%", nameOrig).replace("%items%", String.valueOf(amount));
|
||||
meta.setDisplayName(nameChest);
|
||||
chestItem.setItemMeta(meta);
|
||||
}
|
||||
|
||||
return chestItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<ItemStack> getCustomDrops(@NotNull Player player, @NotNull ItemStack item, @NotNull Block block, int level) {
|
||||
if (block.getType() == Material.ENDER_CHEST) return Collections.emptyList();
|
||||
if (!(block.getState() instanceof Chest chest)) return Collections.emptyList();
|
||||
|
||||
return Collections.singletonList(this.getSilkChest(chest));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEventMustHaveDrops() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
Block block = e.getBlock();
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (EnchantTelekinesis.isDropHandled(block)) return false;
|
||||
if (block.getType() == Material.ENDER_CHEST) return false;
|
||||
if (this.isEventMustHaveDrops() && !e.isDropItems()) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!(block.getState() instanceof Chest chest)) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
// Drop custom chest and do not drop the original one.
|
||||
this.getCustomDrops(player, item, block, level).forEach(chestItem -> block.getWorld().dropItemNaturally(block.getLocation(), chestItem));
|
||||
|
||||
// Do not drop chest items.
|
||||
chest.getBlockInventory().clear();
|
||||
e.setDropItems(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onSilkChestPlace(BlockPlaceEvent e) {
|
||||
ItemStack item = e.getItemInHand();
|
||||
if (item.getType().isAir()) return;
|
||||
|
||||
Block block = e.getBlockPlaced();
|
||||
BlockState state = block.getState();
|
||||
if (!(state instanceof Chest chest)) return;
|
||||
|
||||
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)
|
||||
public void onSilkChestStore(InventoryClickEvent e) {
|
||||
Inventory inv = e.getInventory();
|
||||
if (inv.getType() == InventoryType.CRAFTING || inv.getType() == InventoryType.CREATIVE) return;
|
||||
|
||||
ItemStack item = e.getCurrentItem();
|
||||
if (item == null || item.getType().isAir()) return;
|
||||
|
||||
if (this.isSilkChest(item)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onSilkChestHopper(InventoryPickupItemEvent e) {
|
||||
e.setCancelled(this.isSilkChest(e.getItem().getItemStack()));
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Container;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
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.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.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CustomDropEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class EnchantSmelter extends IEnchantChanceTemplate implements BlockBreakEnchant, CustomDropEnchant {
|
||||
|
||||
private final String sound;
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
private final Map<Material, Material> smeltingTable;
|
||||
|
||||
public static final String ID = "smelter";
|
||||
|
||||
public EnchantSmelter(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
this.sound = cfg.getString("Settings.Sound", "");
|
||||
this.particleName = cfg.getString("Settings.Particle.Name", Particle.FLAME.name());
|
||||
this.particleData = cfg.getString("Settings.Particle.Data", "");
|
||||
this.smeltingTable = new HashMap<>();
|
||||
for (String sFrom : cfg.getSection("Settings.Smelting_Table")) {
|
||||
Material mFrom = Material.getMaterial(sFrom.toUpperCase());
|
||||
if (mFrom == null) {
|
||||
plugin.error("[Smelter] Invalid source material '" + sFrom + "' !");
|
||||
continue;
|
||||
}
|
||||
String sTo = cfg.getString("Settings.Smelting_Table." + sFrom, "");
|
||||
Material mTo = Material.getMaterial(sTo.toUpperCase());
|
||||
if (mTo == null) {
|
||||
plugin.error("[Smelter] Invalid result material '" + sTo + "' !");
|
||||
continue;
|
||||
}
|
||||
this.smeltingTable.put(mFrom, mTo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(Enchantment.SILK_TOUCH);
|
||||
this.addConflict(EnchantRegister.DIVINE_TOUCH);
|
||||
}
|
||||
|
||||
@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", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.PICKAXE, FitItemType.AXE, FitItemType.SHOVEL};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<ItemStack> getCustomDrops(@NotNull Player player, @NotNull ItemStack item, @NotNull Block block, int level) {
|
||||
if (block.getState() instanceof Container) return Collections.emptyList();
|
||||
|
||||
List<ItemStack> drops = plugin.getNMS().getBlockDrops(block, player, item);
|
||||
return this.smelt(drops);
|
||||
}
|
||||
|
||||
public boolean isSmeltable(@NotNull Material material) {
|
||||
return this.smeltingTable.containsKey(material);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ItemStack> smelt(@NotNull List<ItemStack> drops) {
|
||||
return drops.stream().peek(drop -> {
|
||||
Material material = this.smeltingTable.get(drop.getType());
|
||||
if (material != null) drop.setType(material);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEventMustHaveDrops() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
Block block = e.getBlock();
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (EnchantTelekinesis.isDropHandled(block)) return false;
|
||||
if (this.isEventMustHaveDrops() && !e.isDropItems()) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
List<ItemStack> defaults = plugin.getNMS().getBlockDrops(block, player, item);
|
||||
List<ItemStack> custom = this.getCustomDrops(player, item, block, level);
|
||||
if (custom.isEmpty() || custom.containsAll(defaults)) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
e.setDropItems(false);
|
||||
|
||||
World world = block.getWorld();
|
||||
Location location = LocationUtil.getCenter(block.getLocation(), true);
|
||||
|
||||
custom.forEach(itemSmelt -> world.dropItem(location, itemSmelt));
|
||||
this.playEffect(block);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Chest;
|
||||
import org.bukkit.block.Container;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
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.LangMessage;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nexmedia.engine.utils.PlayerUtil;
|
||||
import su.nexmedia.engine.utils.StringUtil;
|
||||
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.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CustomDropEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantManager;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantTelekinesis extends IEnchantChanceTemplate implements BlockBreakEnchant {
|
||||
|
||||
public static final String META_BLOCK_DROP_HANDLER = "telekinesis_drop_handler";
|
||||
|
||||
private final LangMessage messageDropReceived;
|
||||
private final String messageItemName;
|
||||
private final String messageItemSeparator;
|
||||
|
||||
public static final String ID = "telekinesis";
|
||||
|
||||
public EnchantTelekinesis(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.HIGHEST);
|
||||
|
||||
this.messageDropReceived = new LangMessage(plugin.lang(), cfg.getString("Settings.Message.Drop_Received", ""));
|
||||
this.messageItemName = StringUtil.color(cfg.getString("Settings.Message.Item_Name", "&7x%item_amount% &f%item_name%"));
|
||||
this.messageItemSeparator = StringUtil.color(cfg.getString("Settings.Message.Item_Separator", "&7, "));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.remove("Settings.Radius");
|
||||
cfg.remove("Settings.Power");
|
||||
|
||||
cfg.addMissing("Settings.Message.Drop_Received", "{message: ~type: ACTION_BAR; ~prefix: false;}%items%");
|
||||
cfg.addMissing("Settings.Message.Item_Name", "&7x%item_amount% &f%item_name%");
|
||||
cfg.addMissing("Settings.Message.Item_Separator", "&7, ");
|
||||
}
|
||||
|
||||
public static boolean isDropHandled(@NotNull Block block) {
|
||||
return block.hasMetadata(META_BLOCK_DROP_HANDLER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return super.replacePlaceholders(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.TOOL};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (e.getBlock().getState() instanceof Container) return false;
|
||||
if (!e.isDropItems()) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
EnchantCurseOfMisfortune curseOfMisfortune = EnchantRegister.CURSE_OF_MISFORTUNE;
|
||||
if (curseOfMisfortune != null && item.containsEnchantment(curseOfMisfortune)) {
|
||||
if (curseOfMisfortune.use(e, player, item, level)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Block block = e.getBlock();
|
||||
List<ItemStack> drops = new ArrayList<>(plugin.getNMS().getBlockDrops(block, player, item));
|
||||
|
||||
// Check inventory space.
|
||||
if (drops.stream().anyMatch(itemDrop -> PlayerUtil.countItemSpace(player, itemDrop) == 0)) return false;
|
||||
|
||||
// Tell other enchantments that block drops are handled by Telekinesis.
|
||||
block.setMetadata(META_BLOCK_DROP_HANDLER, new FixedMetadataValue(plugin, true));
|
||||
|
||||
for (Map.Entry<CustomDropEnchant, Integer> entry : EnchantManager.getItemCustomEnchants(item, CustomDropEnchant.class).entrySet()) {
|
||||
CustomDropEnchant dropEnchant = entry.getKey();
|
||||
int dropLevel = entry.getValue();
|
||||
if (dropEnchant.isEventMustHaveDrops() && !e.isDropItems()) continue;
|
||||
|
||||
if (dropEnchant instanceof IEnchantChanceTemplate chanceEnchant) {
|
||||
if (!chanceEnchant.checkTriggerChance(dropLevel)) continue;
|
||||
}
|
||||
if (dropEnchant instanceof EnchantSilkChest && block.getState() instanceof Chest) {
|
||||
drops.removeIf(drop -> drop.getType() == block.getType());
|
||||
}
|
||||
if (dropEnchant instanceof EnchantSmelter smelter) {
|
||||
boolean isSmelted = drops.stream().anyMatch(drop -> smelter.isSmeltable(drop.getType()));
|
||||
smelter.smelt(drops);
|
||||
if (isSmelted) smelter.playEffect(block);
|
||||
continue; // Do not add smelted items twice, only replace current ones.
|
||||
}
|
||||
if (dropEnchant instanceof EnchantTreasures treasures) {
|
||||
if (treasures.getTreasure(block) != null) {
|
||||
treasures.playEffect(block);
|
||||
}
|
||||
}
|
||||
|
||||
drops.addAll(dropEnchant.getCustomDrops(player, item, block, dropLevel));
|
||||
}
|
||||
drops.removeIf(Objects::isNull);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
drops.forEach(drop -> {
|
||||
PlayerUtil.addItem(player, drop);
|
||||
|
||||
if (!builder.isEmpty()) builder.append(this.messageItemSeparator);
|
||||
builder.append(this.messageItemName
|
||||
.replace("%item_name%", ItemUtil.getItemName(drop))
|
||||
.replace("%item_amount%", String.valueOf(drop.getAmount())));
|
||||
});
|
||||
this.messageDropReceived.replace("%items%", builder.toString()).send(player);
|
||||
|
||||
e.setDropItems(false);
|
||||
plugin.getServer().getScheduler().runTask(plugin, c -> {
|
||||
block.removeMetadata(META_BLOCK_DROP_HANDLER, plugin);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
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 org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.NexEngine;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.api.manager.ICleanable;
|
||||
import su.nexmedia.engine.manager.player.listener.PlayerBlockPlacedListener;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
import su.nexmedia.engine.utils.LocationUtil;
|
||||
import su.nexmedia.engine.utils.MessageUtil;
|
||||
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.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CustomDropEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class EnchantTreasures extends IEnchantChanceTemplate implements BlockBreakEnchant, CustomDropEnchant, ICleanable {
|
||||
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
private final String sound;
|
||||
private final Map<Material, Map<Material, Double>> treasures;
|
||||
private final Predicate<Block> userBlockFilter;
|
||||
|
||||
public static final String ID = "treasures";
|
||||
|
||||
public EnchantTreasures(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.LOWEST);
|
||||
|
||||
this.particleName = cfg.getString("Settings.Particle.Name", Particle.REDSTONE.name());
|
||||
this.particleData = cfg.getString("Settings.Particle.Data", "200,180,0");
|
||||
this.sound = cfg.getString("Settings.Sound", Sound.BLOCK_NOTE_BLOCK_BELL.name());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
NexEngine.get().getPlayerManager().enableUserBlockListening();
|
||||
PlayerBlockPlacedListener.BLOCK_FILTERS.add(this.userBlockFilter = (block) -> {
|
||||
return this.getTreasure(block) != null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
PlayerBlockPlacedListener.BLOCK_FILTERS.remove(this.userBlockFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
cfg.remove("Settings.Particle_Effect");
|
||||
cfg.addMissing("Settings.Particle.Name", Particle.REDSTONE.name());
|
||||
cfg.addMissing("Settings.Particle.Data", "200,180,0");
|
||||
cfg.addMissing("Settings.Sound", Sound.BLOCK_NOTE_BLOCK_BELL.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.PICKAXE, FitItemType.AXE, FitItemType.SHOVEL};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<ItemStack> getCustomDrops(@NotNull Player player, @NotNull ItemStack item, @NotNull Block block, int level) {
|
||||
ItemStack drop = this.getTreasure(block);
|
||||
if (PlayerBlockPlacedListener.isUserPlaced(block) || drop == null) return Collections.emptyList();
|
||||
return Collections.singletonList(drop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEventMustHaveDrops() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public final ItemStack getTreasure(@NotNull Block block) {
|
||||
Map<Material, Double> treasures = this.treasures.get(block.getType());
|
||||
if (treasures == null) return null;
|
||||
|
||||
Material mat = Rnd.get(treasures);
|
||||
return mat != null && !mat.isAir() ? new ItemStack(mat) : null;
|
||||
}
|
||||
|
||||
public void playEffect(@NotNull Block block) {
|
||||
Location location = LocationUtil.getCenter(block.getLocation());
|
||||
MessageUtil.sound(location, this.sound);
|
||||
EffectUtil.playEffect(location, this.particleName, this.particleData, 0.2f, 0.2f, 0.2f, 0.12f, 20);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
Block block = e.getBlock();
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (EnchantTelekinesis.isDropHandled(block)) return false;
|
||||
if (this.isEventMustHaveDrops() && !e.isDropItems()) return false;
|
||||
if (PlayerBlockPlacedListener.isUserPlaced(block)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
Location location = LocationUtil.getCenter(block.getLocation());
|
||||
List<ItemStack> drops = this.getCustomDrops(player, item, block, level);
|
||||
if (drops.isEmpty()) return false;
|
||||
|
||||
drops.forEach(itemDrop -> block.getWorld().dropItem(location, itemDrop));
|
||||
this.playEffect(block);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
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.Version;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
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.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.hook.HookNCP;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class EnchantTunnel extends IEnchantChanceTemplate implements BlockBreakEnchant {
|
||||
|
||||
private final boolean disableOnSneak;
|
||||
|
||||
public static final String ID = "tunnel";
|
||||
private static final String META_BLOCK_TUNNEL = ID + "_block_tunneled";
|
||||
// X and Z offsets for each block AoE mined
|
||||
private static final int[][] MINING_COORD_OFFSETS = new int[][]{{0, 0}, {0, -1}, {-1, 0}, {0, 1}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1},};
|
||||
private static final Set<Material> INTERACTABLE_BLOCKS = new HashSet<>();
|
||||
|
||||
static {
|
||||
INTERACTABLE_BLOCKS.add(Material.REDSTONE_ORE);
|
||||
if (Version.CURRENT.isHigher(Version.V1_16_R3)) {
|
||||
INTERACTABLE_BLOCKS.add(Material.DEEPSLATE_REDSTONE_ORE);
|
||||
}
|
||||
}
|
||||
|
||||
public EnchantTunnel(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.HIGH);
|
||||
this.disableOnSneak = cfg.getBoolean("Settings.Ignore_When_Sneaking");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.VEINMINER);
|
||||
this.addConflict(EnchantRegister.BLAST_MINING);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.PICKAXE, FitItemType.SHOVEL};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack item, int level) {
|
||||
Block block = e.getBlock();
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (this.disableOnSneak && player.isSneaking()) return false;
|
||||
if (EnchantRegister.VEINMINER != null && item.containsEnchantment(EnchantRegister.VEINMINER)) return false;
|
||||
if (EnchantRegister.BLAST_MINING != null && item.containsEnchantment(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();
|
||||
boolean isZ = dir == BlockFace.EAST || dir == BlockFace.WEST;
|
||||
|
||||
// Mine + shape if Tunnel I, 3x3 if Tunnel II
|
||||
int blocksBroken = 1;
|
||||
if (level == 1) blocksBroken = 2;
|
||||
else if (level == 2) blocksBroken = 5;
|
||||
else if (level == 3) blocksBroken = 9;
|
||||
|
||||
HookNCP.exemptBlocks(player);
|
||||
|
||||
for (int i = 0; i < blocksBroken; i++) {
|
||||
if (item.getType().isAir()) break;
|
||||
|
||||
int xAdd = MINING_COORD_OFFSETS[i][0];
|
||||
int zAdd = MINING_COORD_OFFSETS[i][1];
|
||||
|
||||
Block blockAdd;
|
||||
if (isY) {
|
||||
blockAdd = block.getLocation().clone().add(isZ ? 0 : xAdd, zAdd, isZ ? xAdd : 0).getBlock();
|
||||
}
|
||||
else {
|
||||
blockAdd = block.getLocation().clone().add(xAdd, 0, zAdd).getBlock();
|
||||
}
|
||||
|
||||
// Skip blocks that should not be mined
|
||||
if (blockAdd.equals(block)) continue;
|
||||
if (blockAdd.getDrops(item).isEmpty()) continue;
|
||||
if (blockAdd.isLiquid()) continue;
|
||||
|
||||
Material addType = blockAdd.getType();
|
||||
|
||||
// Some extra block checks.
|
||||
if (addType.isInteractable() && !INTERACTABLE_BLOCKS.contains(addType)) continue;
|
||||
if (addType == Material.BEDROCK || addType == Material.END_PORTAL || addType == Material.END_PORTAL_FRAME) continue;
|
||||
if (addType == Material.OBSIDIAN && addType != block.getType()) continue;
|
||||
|
||||
// Play block break particles before it's broken.
|
||||
EffectUtil.playEffect(LocationUtil.getCenter(blockAdd.getLocation()), Particle.BLOCK_CRACK.name(), blockAdd.getType().name(), 0.2, 0.2, 0.2, 0.1, 20);
|
||||
|
||||
// Add metadata to prevent enchantment triggering in a loop.
|
||||
blockAdd.setMetadata(META_BLOCK_TUNNEL, new FixedMetadataValue(plugin, true));
|
||||
plugin.getNMS().breakBlock(player, blockAdd);
|
||||
blockAdd.removeMetadata(META_BLOCK_TUNNEL, plugin);
|
||||
}
|
||||
|
||||
HookNCP.unexemptBlocks(player);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.tool;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
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.manager.leveling.Scaler;
|
||||
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.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.hook.HookNCP;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.manager.type.FitItemType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class EnchantVeinminer extends IEnchantChanceTemplate implements BlockBreakEnchant {
|
||||
|
||||
private final Scaler blocksLimit;
|
||||
private final 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);
|
||||
|
||||
this.blocksLimit = new EnchantScaler(this, "Settings.Blocks.Max_At_Once");
|
||||
this.blocksAffected = cfg.getStringSet("Settings.Blocks.Affected").stream()
|
||||
.map(type -> Material.getMaterial(type.toUpperCase())).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.TUNNEL);
|
||||
this.addConflict(EnchantRegister.BLAST_MINING);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<Material> getBlocksAffected() {
|
||||
return this.blocksAffected;
|
||||
}
|
||||
|
||||
public int getBlocksLimit(int level) {
|
||||
return (int) this.blocksLimit.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return str -> super.replacePlaceholders(level).apply(str
|
||||
.replace(PLACEHOLDER_BLOCK_LIMIT, String.valueOf(this.getBlocksLimit(level)))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FitItemType[] getFitItemTypes() {
|
||||
return new FitItemType[]{FitItemType.PICKAXE};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<Block> getNearby(@NotNull Block block) {
|
||||
return Stream.of(AREA).map(block::getRelative)
|
||||
.filter(blockAdded -> blockAdded.getType() == block.getType()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private void vein(@NotNull Player player, @NotNull Block source, int level) {
|
||||
Set<Block> ores = new HashSet<>();
|
||||
Set<Block> prepare = new HashSet<>(this.getNearby(source));
|
||||
|
||||
int limit = Math.min(this.getBlocksLimit(level), 30);
|
||||
if (limit < 0) return;
|
||||
|
||||
while (ores.addAll(prepare) && ores.size() < limit) {
|
||||
Set<Block> nearby = new HashSet<>();
|
||||
prepare.forEach(prepared -> nearby.addAll(this.getNearby(prepared)));
|
||||
prepare.clear();
|
||||
prepare.addAll(nearby);
|
||||
}
|
||||
ores.remove(source);
|
||||
ores.forEach(ore -> {
|
||||
// Play block break particles before the block broken.
|
||||
EffectUtil.playEffect(LocationUtil.getCenter(ore.getLocation()), Particle.BLOCK_CRACK.name(), ore.getType().name(), 0.2, 0.2, 0.2, 0.1, 20);
|
||||
|
||||
ore.setMetadata(META_BLOCK_VEINED, new FixedMetadataValue(plugin, true));
|
||||
plugin.getNMS().breakBlock(player, ore);
|
||||
ore.removeMetadata(META_BLOCK_VEINED, plugin);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull BlockBreakEvent e, @NotNull Player player, @NotNull ItemStack tool, int level) {
|
||||
if (!this.isEnchantmentAvailable(player)) return false;
|
||||
if (EnchantRegister.TUNNEL != null && tool.containsEnchantment(EnchantRegister.TUNNEL)) return false;
|
||||
if (EnchantRegister.BLAST_MINING != null && tool.containsEnchantment(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);
|
||||
this.vein(player, block, level);
|
||||
HookNCP.unexemptBlocks(player);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
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.JYML;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
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.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantBaneOfNetherspawn extends IEnchantChanceTemplate implements CombatEnchant {
|
||||
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
private final boolean damageModifier;
|
||||
private final Scaler damageFormula;
|
||||
private final Set<EntityType> entityTypes;
|
||||
|
||||
public static final String ID = "bane_of_netherspawn";
|
||||
|
||||
private static final String PLACEHOLDER_DAMAGE = "%enchantment_damage%";
|
||||
|
||||
public EnchantBaneOfNetherspawn(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
this.particleName = cfg.getString("Settings.Particle.Name", "");
|
||||
this.particleData = cfg.getString("Settings.Particle.Data", "");
|
||||
this.damageModifier = cfg.getBoolean("Settings.Damage.As_Modifier");
|
||||
this.damageFormula = new EnchantScaler(this, "Settings.Damage.Formula");
|
||||
|
||||
this.entityTypes = Sets.newHashSet(EntityType.BLAZE, EntityType.MAGMA_CUBE,
|
||||
EntityType.WITHER_SKELETON, EntityType.GHAST, EntityType.WITHER);
|
||||
|
||||
this.entityTypes.add(EntityType.PIGLIN);
|
||||
this.entityTypes.add(EntityType.PIGLIN_BRUTE);
|
||||
this.entityTypes.add(EntityType.ZOGLIN);
|
||||
this.entityTypes.add(EntityType.HOGLIN);
|
||||
this.entityTypes.add(EntityType.STRIDER);
|
||||
this.entityTypes.add(EntityType.ZOMBIFIED_PIGLIN);
|
||||
}
|
||||
|
||||
public double getDamageModifier(int level) {
|
||||
return this.damageFormula.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.remove("Settings.Particle_Effect");
|
||||
cfg.addMissing("Settings.Particle.Name", Particle.SMOKE_NORMAL.name());
|
||||
cfg.addMissing("Settings.Particle.Data", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.VILLAGE_DEFENDER);
|
||||
this.addConflict(Enchantment.DAMAGE_ARTHROPODS);
|
||||
this.addConflict(Enchantment.DAMAGE_UNDEAD);
|
||||
this.addConflict(Enchantment.DAMAGE_ALL);
|
||||
}
|
||||
|
||||
@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 use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.isEnchantmentAvailable(damager)) return false;
|
||||
if (!this.entityTypes.contains(victim.getType())) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(damager)) return false;
|
||||
|
||||
double damageEvent = e.getDamage();
|
||||
double damageAdd = this.getDamageModifier(level);
|
||||
e.setDamage(this.damageModifier ? damageEvent * damageAdd : damageEvent + damageAdd);
|
||||
EffectUtil.playEffect(victim.getEyeLocation(), this.particleName, this.particleData, 0.25, 0.25, 0.25, 0.1f, 30);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantBlindness extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "blindness";
|
||||
|
||||
public EnchantBlindness(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.BLINDNESS);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantConfusion extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "confusion";
|
||||
|
||||
public EnchantConfusion(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.CONFUSION);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
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.api.config.JYML;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
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.type.CombatEnchant;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class EnchantCure extends IEnchantChanceTemplate implements CombatEnchant {
|
||||
|
||||
private final Sound sound;
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
|
||||
public static final String ID = "cure";
|
||||
|
||||
private static final Set<EntityType> MOBS_TO_CURE = Sets.newHashSet(EntityType.ZOMBIFIED_PIGLIN, EntityType.ZOMBIE_VILLAGER);
|
||||
|
||||
public EnchantCure(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
this.sound = cfg.getEnum("Settings.Sound", Sound.class);
|
||||
this.particleName = cfg.getString("Settings.Particle.Name", Particle.CLOUD.name());
|
||||
this.particleData = cfg.getString("Settings.Particle.Data", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.remove("Settings.Particle_Effect");
|
||||
cfg.addMissing("Settings.Particle.Name", Particle.CLOUD.name());
|
||||
cfg.addMissing("Settings.Particle.Data", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public 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 (!MOBS_TO_CURE.contains(victim.getType())) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(damager)) return false;
|
||||
|
||||
e.setCancelled(true);
|
||||
|
||||
EffectUtil.playEffect(victim.getLocation(), this.particleName, this.particleData, 0.25, 0.25, 0.25, 0.1f, 20);
|
||||
if (this.sound != null) MessageUtil.sound(victim.getLocation(), this.sound);
|
||||
|
||||
if (victim instanceof PigZombie pigZombie) {
|
||||
victim.getWorld().spawn(victim.getLocation(), Piglin.class);
|
||||
}
|
||||
else if (victim instanceof ZombieVillager zombieVillager) {
|
||||
Villager.Profession profession = zombieVillager.getVillagerProfession();
|
||||
Villager villager = victim.getWorld().spawn(victim.getLocation(), Villager.class);
|
||||
if (profession != null) {
|
||||
villager.setProfession(profession);
|
||||
}
|
||||
}
|
||||
victim.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
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.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
import su.nexmedia.engine.utils.MessageUtil;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
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.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantCutter extends IEnchantChanceTemplate implements CombatEnchant {
|
||||
|
||||
protected Scaler durabilityReduction;
|
||||
protected Sound sound;
|
||||
|
||||
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);
|
||||
this.durabilityReduction = new EnchantScaler(this, "Settings.Item.Durability_Reduction");
|
||||
this.sound = cfg.getEnum("Settings.Item.Sound", Sound.class);
|
||||
}
|
||||
|
||||
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))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public 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;
|
||||
|
||||
EntityEquipment equipment = victim.getEquipment();
|
||||
if (equipment == null) return false;
|
||||
|
||||
ItemStack[] armor = equipment.getArmorContents();
|
||||
if (armor.length == 0) return false;
|
||||
|
||||
int get = Rnd.get(armor.length);
|
||||
ItemStack itemCut = armor[get];
|
||||
|
||||
if (itemCut == null || itemCut.getType().isAir() || itemCut.getType().getMaxDurability() == 0) return false;
|
||||
|
||||
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);
|
||||
|
||||
armor[get] = null;
|
||||
equipment.setArmorContents(armor);
|
||||
|
||||
Item drop = victim.getWorld().dropItemNaturally(victim.getLocation(), itemCut);
|
||||
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);
|
||||
if (this.sound != null) MessageUtil.sound(victim.getLocation(), this.sound.name());
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.*;
|
||||
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.JYML;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nexmedia.engine.utils.StringUtil;
|
||||
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.type.DeathEnchant;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class EnchantDecapitator extends IEnchantChanceTemplate implements DeathEnchant {
|
||||
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
private final Set<String> ignoredEntityTypes;
|
||||
private final String headName;
|
||||
private final Map<String, String> headTextures;
|
||||
|
||||
public static final String ID = "decapitator";
|
||||
|
||||
public EnchantDecapitator(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
this.particleName = cfg.getString("Settings.Particle.Name", Particle.BLOCK_CRACK.name());
|
||||
this.particleData = cfg.getString("Settings.Particle.Data", Material.REDSTONE_BLOCK.name());
|
||||
this.ignoredEntityTypes = cfg.getStringSet("Settings.Ignored_Entity_Types").stream().map(String::toUpperCase).collect(Collectors.toSet());
|
||||
this.headName = StringUtil.color(cfg.getString("Settings.Head_Item.Name", "&c%entity%'s Head"));
|
||||
this.headTextures = new HashMap<>();
|
||||
for (String sType : cfg.getSection("Settings.Head_Item.Textures")) {
|
||||
String texture = cfg.getString("Settings.Head_Item.Textures." + sType);
|
||||
this.headTextures.put(sType.toUpperCase(), texture);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
this.cfg.remove("Settings.Particle_Effect");
|
||||
this.cfg.addMissing("Settings.Particle.Name", Particle.BLOCK_CRACK.name());
|
||||
this.cfg.addMissing("Settings.Particle.Data", Material.REDSTONE_BLOCK.name());
|
||||
this.cfg.addMissing("Settings.Ignored_Entity_Types", Arrays.asList("ENDER_DRAGON", "WITHER_SKELETON", "WITHER"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity victim, int level) {
|
||||
if (!this.isEnchantmentAvailable(victim)) return false;
|
||||
|
||||
EntityType entityType = victim.getType();
|
||||
if (this.ignoredEntityTypes.contains(entityType.name())) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
Player killer = victim.getKiller();
|
||||
if (killer == null) return false;
|
||||
if (!this.takeCostItem(killer)) 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 (victim instanceof Player player) {
|
||||
entityName = this.headName.replace("%entity%", victim.getName());
|
||||
meta.setOwningPlayer(player);
|
||||
}
|
||||
else {
|
||||
String texture = this.headTextures.get(victim.getType().name());
|
||||
if (texture == null) return false;
|
||||
|
||||
entityName = this.headName.replace("%entity%", plugin.lang().getEnum(victim.getType()));
|
||||
ItemUtil.addSkullTexture(item, texture, ID + victim.getType().name());
|
||||
meta = (SkullMeta) item.getItemMeta();
|
||||
}
|
||||
|
||||
meta.setDisplayName(entityName);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
|
||||
victim.getWorld().dropItemNaturally(victim.getLocation(), item);
|
||||
EffectUtil.playEffect(victim.getEyeLocation(), this.particleName, this.particleData, 0.2f, 0.15f, 0.2f, 0.15f, 40);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.api.config.JYML;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
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.type.CombatEnchant;
|
||||
|
||||
public class EnchantDoubleStrike extends IEnchantChanceTemplate implements CombatEnchant {
|
||||
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
private final Sound sound;
|
||||
|
||||
public static final String ID = "double_strike";
|
||||
|
||||
public EnchantDoubleStrike(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.LOW);
|
||||
|
||||
this.particleName = cfg.getString("Settings.Particle.Name", Particle.EXPLOSION_NORMAL.name());
|
||||
this.particleData = cfg.getString("Settings.Particle.Data", "");
|
||||
this.sound = cfg.getEnum("Settings.Sound", Sound.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.remove("Settings.Particle_Effect");
|
||||
cfg.addMissing("Settings.Particle.Name", Particle.EXPLOSION_NORMAL.name());
|
||||
cfg.addMissing("Settings.Particle.Data", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public 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;
|
||||
|
||||
e.setDamage(e.getDamage() * 2D);
|
||||
EffectUtil.playEffect(victim.getEyeLocation(), this.particleName, this.particleData, 0.2f, 0.15f, 0.2f, 0.15f, 20);
|
||||
if (this.sound != null) MessageUtil.sound(victim.getLocation(), this.sound);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantExhaust extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "exhaust";
|
||||
|
||||
public EnchantExhaust(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.HUNGER);
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.manager.leveling.Scaler;
|
||||
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.api.enchantment.type.DeathEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantExpHunter extends IEnchantChanceTemplate implements DeathEnchant {
|
||||
|
||||
private final Scaler expModifier;
|
||||
|
||||
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);
|
||||
this.expModifier = new EnchantScaler(this, "Settings.Exp_Modifier");
|
||||
}
|
||||
|
||||
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
|
||||
.replace(PLACEHOLDER_EXP_MODIFIER, NumberUtil.format(this.getExpModifier(level) * 100D - 100D))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
double expModifier = this.getExpModifier(level);
|
||||
double expFinal = Math.ceil((double) e.getDroppedExp() * expModifier);
|
||||
|
||||
e.setDroppedExp((int) expFinal);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.Version;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantIceAspect extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "ice_aspect";
|
||||
|
||||
public EnchantIceAspect(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.SLOW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!super.use(e, damager, victim, weapon, level)) return false;
|
||||
|
||||
if (Version.CURRENT.isHigher(Version.V1_16_R3)) {
|
||||
victim.setFreezeTicks(victim.getMaxFreezeTicks());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Trident;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
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.manager.leveling.Scaler;
|
||||
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.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantInfernus extends IEnchantChanceTemplate {
|
||||
|
||||
private final Scaler fireTicks;
|
||||
|
||||
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);
|
||||
|
||||
this.fireTicks = new EnchantScaler(this, "Settings.Fire_Ticks");
|
||||
}
|
||||
|
||||
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
|
||||
.replace(PLACEHOLDER_FIRE_DURATION, NumberUtil.format((double) this.getFireTicks(level) / 20D))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.TRIDENT;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onInfernusTridentLaunch(ProjectileLaunchEvent e) {
|
||||
Entity entity = e.getEntity();
|
||||
if (!(entity instanceof Trident trident)) return;
|
||||
if (!(trident.getShooter() instanceof LivingEntity shooter)) return;
|
||||
if (!this.isEnchantmentAvailable(shooter)) return;
|
||||
|
||||
ItemStack item = trident.getItem();
|
||||
|
||||
int level = item.getEnchantmentLevel(this);
|
||||
if (level <= 0) return;
|
||||
|
||||
if (!this.checkTriggerChance(level)) return;
|
||||
if (!this.takeCostItem(shooter)) return;
|
||||
trident.setFireTicks(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onInfernusDamageApply(EntityDamageByEntityEvent e) {
|
||||
Entity entity = e.getDamager();
|
||||
if (!(entity instanceof Trident trident)) return;
|
||||
|
||||
ItemStack item = trident.getItem();
|
||||
|
||||
int level = item.getEnchantmentLevel(this);
|
||||
if (level <= 0 || trident.getFireTicks() <= 0) return;
|
||||
|
||||
int ticks = this.getFireTicks(level);
|
||||
e.getEntity().setFireTicks(ticks);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.PlayerUtil;
|
||||
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.type.DeathEnchant;
|
||||
|
||||
public class EnchantNimble extends IEnchantChanceTemplate implements DeathEnchant {
|
||||
|
||||
public static final String ID = "nimble";
|
||||
|
||||
public EnchantNimble(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.LOWEST);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level) {
|
||||
if (!this.isEnchantmentAvailable(dead)) return false;
|
||||
|
||||
Player player = dead.getKiller();
|
||||
if (player == null) return false;
|
||||
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(player)) return false;
|
||||
|
||||
e.getDrops().forEach(item -> PlayerUtil.addItem(player, item));
|
||||
e.getDrops().clear();
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantParalyze extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "paralyze";
|
||||
|
||||
public EnchantParalyze(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.SLOW_DIGGING);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantRage extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "rage";
|
||||
|
||||
public EnchantRage(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.INCREASE_DAMAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return super.use(e, damager, damager, weapon, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.api.config.JYML;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.EntityUtil;
|
||||
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.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
public class EnchantRocket extends IEnchantChanceTemplate implements CombatEnchant {
|
||||
|
||||
private final Scaler fireworkPower;
|
||||
|
||||
public static final String ID = "rocket";
|
||||
|
||||
public EnchantRocket(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
this.fireworkPower = new EnchantScaler(this, "Settings.Firework_Power");
|
||||
}
|
||||
|
||||
public final double getFireworkPower(int level) {
|
||||
return this.fireworkPower.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public 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 (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;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
import org.bukkit.Material;
|
||||
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.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.utils.CollectionsUtil;
|
||||
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.type.DeathEnchant;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EnchantScavenger extends IEnchantChanceTemplate implements DeathEnchant {
|
||||
|
||||
private final Map<EntityType, Map<Material, Map.Entry<int[], Double>>> loot;
|
||||
|
||||
public static final String ID = "scavenger";
|
||||
|
||||
public EnchantScavenger(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
this.loot = new HashMap<>();
|
||||
|
||||
for (String eId : cfg.getSection("Settings.Treasures")) {
|
||||
EntityType eType = CollectionsUtil.getEnum(eId, EntityType.class);
|
||||
if (eType == null || !eType.isAlive()) {
|
||||
plugin.error("[Scavenger] Invalid entity type '" + eId + "' !");
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<Material, Map.Entry<int[], Double>> items = new HashMap<>();
|
||||
for (String sFromArray : cfg.getSection("Settings.Treasures." + eId)) {
|
||||
Material material = Material.getMaterial(sFromArray.toUpperCase());
|
||||
if (material == null) {
|
||||
plugin.error("[Scavenger] Invalid item material '" + sFromArray + "' !");
|
||||
continue;
|
||||
}
|
||||
|
||||
String path = "Settings.Treasures." + eId + "." + sFromArray + ".";
|
||||
String[] amountSplit = cfg.getString(path + "Amount", "1:1").split(":");
|
||||
int amountMin = StringUtil.getInteger(amountSplit[0], 1);
|
||||
int amountMax = StringUtil.getInteger(amountSplit[1], 1);
|
||||
int[] amount = new int[]{amountMin, amountMax};
|
||||
|
||||
double chance = cfg.getDouble(path + "Chance");
|
||||
if (chance <= 0) continue;
|
||||
|
||||
Map.Entry<int[], Double> item = new AbstractMap.SimpleEntry<>(amount, chance);
|
||||
items.put(material, item);
|
||||
}
|
||||
this.loot.put(eType, items);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull EntityDeathEvent e, @NotNull LivingEntity dead, int level) {
|
||||
if (!this.isEnchantmentAvailable(dead)) return false;
|
||||
|
||||
Map<Material, Map.Entry<int[], Double>> items = this.loot.get(dead.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();
|
||||
if (Rnd.get(true) > chance) return;
|
||||
|
||||
int amount = Rnd.get(data.getKey()[0], data.getKey()[1]);
|
||||
if (amount <= 0) return;
|
||||
|
||||
ItemStack item = new ItemStack(material);
|
||||
e.getDrops().add(item);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantSurprise extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "surprise";
|
||||
|
||||
public EnchantSurprise(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.BLINDNESS);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(@NotNull EntityDamageByEntityEvent e, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
this.potionEffectType = Rnd.get(PotionEffectType.values());
|
||||
return super.use(e, damager, victim, weapon, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.JYML;
|
||||
import su.nexmedia.engine.utils.PDCUtil;
|
||||
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.type.DeathEnchant;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class EnchantThrifty extends IEnchantChanceTemplate implements DeathEnchant {
|
||||
|
||||
private final Set<String> ignoredEntityTypes;
|
||||
private final Set<String> ignoredSpawnReasons;
|
||||
private final NamespacedKey keyEntityIgnored;
|
||||
|
||||
public static final String ID = "thrifty";
|
||||
|
||||
public EnchantThrifty(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
this.keyEntityIgnored = new NamespacedKey(plugin, ID + "_ignored");
|
||||
|
||||
this.ignoredEntityTypes = cfg.getStringSet("Settings.Ignored_Entity_Types").stream().map(String::toUpperCase).collect(Collectors.toSet());
|
||||
this.ignoredSpawnReasons = cfg.getStringSet("Settings.Ignored_Spawn_Reasons").stream().map(String::toUpperCase).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@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.ignoredEntityTypes.contains(dead.getType().name())) return false;
|
||||
if (PDCUtil.getBooleanData(dead, this.keyEntityIgnored)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
Material material = Material.getMaterial(dead.getType().name() + "_SPAWN_EGG");
|
||||
if (material == null) {
|
||||
if (dead.getType() == EntityType.MUSHROOM_COW) {
|
||||
material = Material.MOOSHROOM_SPAWN_EGG;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
if (!this.takeCostItem(killer)) return false;
|
||||
|
||||
ItemStack egg = new ItemStack(material);
|
||||
e.getDrops().add(egg);
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onSettingCreatureSpawnReason(CreatureSpawnEvent e) {
|
||||
if (!this.ignoredSpawnReasons.contains(e.getSpawnReason().name())) return;
|
||||
|
||||
PDCUtil.setData(e.getEntity(), this.keyEntityIgnored, true);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.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.JYML;
|
||||
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.type.CombatEnchant;
|
||||
|
||||
public class EnchantThunder extends IEnchantChanceTemplate implements CombatEnchant {
|
||||
|
||||
private final boolean inThunderstormOnly;
|
||||
|
||||
public static final String ID = "thunder";
|
||||
|
||||
public EnchantThunder(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
this.inThunderstormOnly = cfg.getBoolean("Settings.During_Thunderstorm_Only");
|
||||
}
|
||||
|
||||
public boolean isInThunderstormOnly() {
|
||||
return inThunderstormOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public 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.isInThunderstormOnly() && !victim.getWorld().isThundering()) return false;
|
||||
if (victim.getLocation().getBlock().getLightFromSky() != 15) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(damager)) return false;
|
||||
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
victim.setNoDamageTicks(0);
|
||||
victim.getWorld().strikeLightning(victim.getLocation());
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.manager.leveling.Scaler;
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantChanceTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantVampire extends IEnchantChanceTemplate implements CombatEnchant {
|
||||
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
private final Scaler healAmount;
|
||||
private final boolean healMultiplier;
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
public double getHealAmount(int level) {
|
||||
return this.healAmount.getValue(level);
|
||||
}
|
||||
|
||||
public boolean isHealMultiplier() {
|
||||
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 * " + PLACEHOLDER_LEVEL);
|
||||
cfg.addMissing("Settings.Heal.As_Multiplier", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getItemTarget() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
double healAmount = this.getHealAmount(level);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
EntityRegainHealthEvent healthEvent = new EntityRegainHealthEvent(damager, healFinal, EntityRegainHealthEvent.RegainReason.CUSTOM);
|
||||
plugin.getPluginManager().callEvent(healthEvent);
|
||||
if (healthEvent.isCancelled()) return false;
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantVenom extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "venom";
|
||||
|
||||
public EnchantVenom(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.POISON);
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Illager;
|
||||
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.manager.leveling.Scaler;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
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.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantScaler;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class EnchantVillageDefender extends IEnchantChanceTemplate implements CombatEnchant {
|
||||
|
||||
private final boolean damageMultiplier;
|
||||
private final Scaler damageAmount;
|
||||
private final String particleName;
|
||||
private final String particleData;
|
||||
|
||||
public static final String ID = "village_defender";
|
||||
public static final String PLACEHOLDER_DAMAGE_AMOUNT = "%enchantment_damage_amount%";
|
||||
|
||||
public EnchantVillageDefender(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM);
|
||||
|
||||
this.damageAmount = new EnchantScaler(this, "Settings.Damage.Formula");
|
||||
this.damageMultiplier = cfg.getBoolean("Settings.Damage.As_Modifier");
|
||||
this.particleName = cfg.getString("Settings.Particle.Name", Particle.VILLAGER_ANGRY.name());
|
||||
this.particleData = cfg.getString("Settings.Particle.Data", "");
|
||||
}
|
||||
|
||||
public double getDamageAddict(int level) {
|
||||
return this.damageAmount.getValue(level);
|
||||
}
|
||||
|
||||
public boolean isDamageMultiplier() {
|
||||
return damageMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return str -> super.replacePlaceholders(level).apply(str
|
||||
.replace(PLACEHOLDER_DAMAGE_AMOUNT, NumberUtil.format(this.getDamageAddict(level)))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateConfig() {
|
||||
super.updateConfig();
|
||||
|
||||
cfg.remove("Settings.Particle_Effect");
|
||||
cfg.addMissing("Settings.Particle.Name", Particle.VILLAGER_ANGRY.name());
|
||||
cfg.addMissing("Settings.Particle.Data", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConflicts() {
|
||||
super.addConflicts();
|
||||
this.addConflict(EnchantRegister.BANE_OF_NETHERSPAWN);
|
||||
this.addConflict(Enchantment.DAMAGE_ARTHROPODS);
|
||||
this.addConflict(Enchantment.DAMAGE_UNDEAD);
|
||||
this.addConflict(Enchantment.DAMAGE_ALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public 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 (!(victim instanceof Illager)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.takeCostItem(damager)) return false;
|
||||
|
||||
double damageAdd = this.getDamageAddict(level);
|
||||
double damageHas = e.getDamage();
|
||||
double damageFinal = this.isDamageMultiplier() ? (damageHas * damageAdd) : (damageHas + damageAdd);
|
||||
|
||||
e.setDamage(damageFinal);
|
||||
EffectUtil.playEffect(victim.getEyeLocation(), this.particleName, this.particleData, 0.15, 0.15, 0.15, 0.13f, 3);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.manager.enchants.weapon;
|
||||
|
||||
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.EnchantPriority;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantCombatPotionTemplate;
|
||||
|
||||
public class EnchantWither extends IEnchantCombatPotionTemplate {
|
||||
|
||||
public static final String ID = "wither";
|
||||
|
||||
public EnchantWither(@NotNull ExcellentEnchants plugin, @NotNull JYML cfg) {
|
||||
super(plugin, cfg, EnchantPriority.MEDIUM, PotionEffectType.WITHER);
|
||||
}
|
||||
}
|
@ -0,0 +1,283 @@
|
||||
package su.nightexpress.excellentenchants.manager.listeners;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Chest;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Minecart;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.enchantment.EnchantItemEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.VillagerAcquireTradeEvent;
|
||||
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.event.player.PlayerFishEvent;
|
||||
import org.bukkit.event.world.LootGenerateEvent;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.manager.AbstractListener;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
import su.nightexpress.excellentenchants.config.ObtainSettings;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantManager;
|
||||
import su.nightexpress.excellentenchants.manager.object.EnchantTier;
|
||||
import su.nightexpress.excellentenchants.manager.type.ObtainType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EnchantGenericListener extends AbstractListener<ExcellentEnchants> {
|
||||
|
||||
public EnchantGenericListener(@NotNull EnchantManager enchantManager) {
|
||||
super(enchantManager.plugin());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Handle Anvil
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onEnchantUpdateAnvil(PrepareAnvilEvent e) {
|
||||
AnvilInventory inventory = e.getInventory();
|
||||
|
||||
ItemStack first = inventory.getItem(0);
|
||||
ItemStack second = inventory.getItem(1);
|
||||
ItemStack result = e.getResult();
|
||||
|
||||
// Check if source item is an enchantable single item.
|
||||
if (first == null || !EnchantManager.isEnchantable(first) || first.getAmount() > 1) return;
|
||||
|
||||
// For repair/rename, only re-add item enchants.
|
||||
if ((second == null || second.getType().isAir() || !EnchantManager.isEnchantable(second)) && (result != null && result.getType() == first.getType())) {
|
||||
ItemStack result2 = new ItemStack(result);
|
||||
EnchantManager.getItemCustomEnchants(first).forEach((hasEnch, hasLevel) -> {
|
||||
EnchantManager.addEnchant(result2, hasEnch, hasLevel, true);
|
||||
});
|
||||
e.setResult(result2);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the second item is an enchantable single item.
|
||||
if (second == null || second.getAmount() > 1 || !EnchantManager.isEnchantable(second)) return;
|
||||
|
||||
// Prevent operation if first item is book while the second one is another item.
|
||||
if (first.getType() == Material.ENCHANTED_BOOK && second.getType() != first.getType()) return;
|
||||
|
||||
// Fine result item in case if it's nulled somehow.
|
||||
if (result == null || result.getType() == Material.AIR) {
|
||||
result = new ItemStack(first);
|
||||
}
|
||||
|
||||
Map<ExcellentEnchant, Integer> enchAdd = EnchantManager.getItemCustomEnchants(first);
|
||||
int repairCost = inventory.getRepairCost();
|
||||
|
||||
// If the second item is an enchanted book or the same item type, then
|
||||
// we can merge our enchantments.
|
||||
if (second.getType() == Material.ENCHANTED_BOOK || second.getType() == first.getType()) {
|
||||
for (Map.Entry<ExcellentEnchant, Integer> en : EnchantManager.getItemCustomEnchants(second).entrySet()) {
|
||||
enchAdd.merge(en.getKey(), en.getValue(), (oldLvl, newLvl) -> (oldLvl.equals(newLvl)) ? (oldLvl + 1) : (Math.max(oldLvl, newLvl)));
|
||||
}
|
||||
}
|
||||
|
||||
// Recalculate operation cost depends on enchantments merge cost.
|
||||
for (Map.Entry<ExcellentEnchant, Integer> ent : enchAdd.entrySet()) {
|
||||
ExcellentEnchant enchant = ent.getKey();
|
||||
int level = Math.min(enchant.getMaxLevel(), ent.getValue());
|
||||
if (EnchantManager.addEnchant(result, enchant, level, false)) {
|
||||
repairCost += enchant.getAnvilMergeCost(level);
|
||||
}
|
||||
}
|
||||
|
||||
if (!first.equals(result)) {
|
||||
EnchantManager.updateItemLoreEnchants(result);
|
||||
e.setResult(result);
|
||||
|
||||
// NMS ContainerAnvil will set level cost to 0 right after calling the event
|
||||
// So we have to change it with a 1 tick delay.
|
||||
final int repairCost2 = repairCost;
|
||||
this.plugin.runTask((c) -> inventory.setRepairCost(repairCost2), false);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Update enchantment lore after grindstone
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantUpdateGrindstoneClick(InventoryClickEvent e) {
|
||||
Inventory inventory = e.getInventory();
|
||||
if (inventory.getType() != InventoryType.GRINDSTONE) return;
|
||||
if (e.getRawSlot() == 2) return;
|
||||
|
||||
this.updateGrindstone(inventory);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantUpdateGrindstoneDrag(InventoryDragEvent e) {
|
||||
Inventory inventory = e.getInventory();
|
||||
if (inventory.getType() != InventoryType.GRINDSTONE) return;
|
||||
|
||||
this.updateGrindstone(inventory);
|
||||
}
|
||||
|
||||
private void updateGrindstone(@NotNull Inventory inventory) {
|
||||
this.plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
ItemStack result = inventory.getItem(2);
|
||||
if (result == null || result.getType().isAir()) return;
|
||||
|
||||
Map<ExcellentEnchant, Integer> curses = new HashMap<>();
|
||||
for (int slot = 0; slot < 2; slot++) {
|
||||
ItemStack source = inventory.getItem(slot);
|
||||
if (source == null || source.getType().isAir()) continue;
|
||||
|
||||
curses.putAll(EnchantManager.getItemCustomEnchants(source));
|
||||
}
|
||||
curses.entrySet().removeIf(entry -> !entry.getKey().isCursed());
|
||||
curses.forEach((excellentEnchant, level) -> {
|
||||
EnchantManager.addEnchant(result, excellentEnchant, level, true);
|
||||
});
|
||||
EnchantManager.updateItemLoreEnchants(result);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Handle Enchanting Table
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onEnchantPopulateEnchantingTable(final EnchantItemEvent e) {
|
||||
ObtainSettings settings = Config.getObtainSettings(ObtainType.ENCHANTING);
|
||||
if (settings == null || Rnd.get(true) > settings.getEnchantsCustomGenerationChance()) return;
|
||||
|
||||
ItemStack target = e.getItem();
|
||||
boolean enchantAdded = false;
|
||||
|
||||
int enchMax = settings.getEnchantsTotalMax();
|
||||
int enchRoll = Rnd.get(settings.getEnchantsCustomMin(), settings.getEnchantsCustomMax());
|
||||
|
||||
for (int count = 0; (count < enchRoll && e.getEnchantsToAdd().size() < enchMax); count++) {
|
||||
EnchantTier tier = EnchantManager.getTierByChance(ObtainType.ENCHANTING);
|
||||
if (tier == null) continue;
|
||||
|
||||
ExcellentEnchant enchant = tier.getEnchant(ObtainType.ENCHANTING, target);
|
||||
if (enchant == null) continue;
|
||||
if (e.getEnchantsToAdd().keySet().stream().anyMatch(add -> add.conflictsWith(enchant) || enchant.conflictsWith(add)))
|
||||
continue;
|
||||
|
||||
int level = enchant.getLevelByEnchantCost(e.getExpLevelCost());
|
||||
if (level < 1) continue;
|
||||
|
||||
e.getEnchantsToAdd().put(enchant, level);
|
||||
enchantAdded = true;
|
||||
}
|
||||
|
||||
if (enchantAdded) {
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
ItemStack result = e.getInventory().getItem(0);
|
||||
if (result == null) return;
|
||||
|
||||
// Fix enchantments for Enchant Books.
|
||||
// Enchants are not added on book because they do not exists in NMS.
|
||||
// Server gets enchants from NMS to apply it on Book NBT tags.
|
||||
ItemMeta meta = result.getItemMeta();
|
||||
if (meta instanceof EnchantmentStorageMeta meta2) {
|
||||
e.getEnchantsToAdd().forEach((en, lvl) -> {
|
||||
if (!meta2.hasStoredEnchant(en)) {
|
||||
meta2.addStoredEnchant(en, lvl, true);
|
||||
}
|
||||
});
|
||||
result.setItemMeta(meta2);
|
||||
}
|
||||
|
||||
EnchantManager.updateItemLoreEnchants(result);
|
||||
e.getInventory().setItem(0, result);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Adding Enchants to Villagers
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantPopulateVillagerAcquire(VillagerAcquireTradeEvent e) {
|
||||
MerchantRecipe recipe = e.getRecipe();
|
||||
ItemStack result = recipe.getResult();
|
||||
|
||||
if (!EnchantManager.isEnchantable(result)) return;
|
||||
if (!EnchantManager.populateEnchantments(result, ObtainType.VILLAGER)) return;
|
||||
|
||||
int uses = recipe.getUses();
|
||||
int maxUses = recipe.getMaxUses();
|
||||
boolean expReward = recipe.hasExperienceReward();
|
||||
int villagerExperience = recipe.getVillagerExperience();
|
||||
float priceMultiplier = recipe.getPriceMultiplier();
|
||||
|
||||
MerchantRecipe recipe2 = new MerchantRecipe(result, uses, maxUses, expReward, villagerExperience, priceMultiplier);
|
||||
recipe2.setIngredients(recipe.getIngredients());
|
||||
e.setRecipe(recipe2);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantPopulateLoot(LootGenerateEvent e) {
|
||||
if (Config.getObtainSettings(ObtainType.LOOT_GENERATION) == null) return;
|
||||
|
||||
Entity entity = e.getEntity();
|
||||
InventoryHolder holder = e.getInventoryHolder();
|
||||
|
||||
if (entity instanceof Minecart || holder instanceof Chest) {
|
||||
e.getLoot().forEach(item -> {
|
||||
if (item != null && EnchantManager.isEnchantable(item)) {
|
||||
EnchantManager.populateEnchantments(item, ObtainType.LOOT_GENERATION);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantPopulateFishing(PlayerFishEvent e) {
|
||||
if (Config.getObtainSettings(ObtainType.FISHING) == null) return;
|
||||
if (e.getState() != PlayerFishEvent.State.CAUGHT_FISH) return;
|
||||
if (!(e.getCaught() instanceof Item item)) return;
|
||||
|
||||
ItemStack itemStack = item.getItemStack();
|
||||
if (EnchantManager.isEnchantable(itemStack)) {
|
||||
EnchantManager.populateEnchantments(itemStack, ObtainType.FISHING);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantPopulatePiglinBarter(CreatureSpawnEvent e) {
|
||||
if (Config.getObtainSettings(ObtainType.MOB_SPAWNING) == null) return;
|
||||
|
||||
LivingEntity entity = e.getEntity();
|
||||
EntityEquipment equipment = entity.getEquipment();
|
||||
if (equipment == null) return;
|
||||
|
||||
ItemStack[] armor = equipment.getArmorContents();
|
||||
for (ItemStack item : armor) {
|
||||
if (item != null && EnchantManager.isEnchantable(item)) {
|
||||
EnchantManager.populateEnchantments(item, ObtainType.MOB_SPAWNING);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack itemMain = equipment.getItemInMainHand();
|
||||
if (EnchantManager.isEnchantable(itemMain)) {
|
||||
EnchantManager.populateEnchantments(itemMain, ObtainType.MOB_SPAWNING);
|
||||
}
|
||||
|
||||
ItemStack itemOff = equipment.getItemInOffHand();
|
||||
if (EnchantManager.isEnchantable(itemOff)) {
|
||||
EnchantManager.populateEnchantments(itemOff, ObtainType.MOB_SPAWNING);
|
||||
}
|
||||
|
||||
equipment.setArmorContents(armor);
|
||||
equipment.setItemInMainHand(itemMain);
|
||||
equipment.setItemInOffHand(itemOff);
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
package su.nightexpress.excellentenchants.manager.listeners;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.Event.Result;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.manager.AbstractListener;
|
||||
import su.nexmedia.engine.utils.EntityUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.*;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantManager;
|
||||
|
||||
public class EnchantHandlerListener extends AbstractListener<ExcellentEnchants> {
|
||||
|
||||
public EnchantHandlerListener(@NotNull EnchantManager enchantManager) {
|
||||
super(enchantManager.plugin());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Combat Attacking Enchants
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantCombatMelee(EntityDamageByEntityEvent e) {
|
||||
if (e.getCause() == DamageCause.THORNS) return;
|
||||
if (!(e.getEntity() instanceof LivingEntity victim)) return;
|
||||
if (!(e.getDamager() instanceof LivingEntity damager)) return;
|
||||
|
||||
EntityEquipment equipment = damager.getEquipment();
|
||||
if (equipment == null) return;
|
||||
|
||||
ItemStack weapon = equipment.getItemInMainHand();
|
||||
if (weapon.getType().isAir() || weapon.getType() == Material.ENCHANTED_BOOK) return;
|
||||
|
||||
EnchantManager.getItemCustomEnchants(weapon, CombatEnchant.class).forEach((combatEnchant, level) -> {
|
||||
if (combatEnchant instanceof BowEnchant) return;
|
||||
combatEnchant.use(e, damager, victim, weapon, level);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Armor Defensive Enchants
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantCombatArmor(EntityDamageByEntityEvent e) {
|
||||
// Prevent armor enchants to have effect if damage is from Thorns.
|
||||
if (e.getCause() == DamageCause.THORNS) return;
|
||||
|
||||
Entity eVictim = e.getEntity();
|
||||
if (!(eVictim instanceof LivingEntity victim)) return;
|
||||
|
||||
Entity eDamager = e.getDamager();
|
||||
if (eDamager instanceof Projectile projectile) {
|
||||
if (projectile.getShooter() instanceof Entity) {
|
||||
eDamager = (Entity) projectile.getShooter();
|
||||
}
|
||||
}
|
||||
if (!(eDamager instanceof LivingEntity damager) || eDamager.equals(eVictim)) return;
|
||||
|
||||
EntityEquipment equipDamager = damager.getEquipment();
|
||||
if (equipDamager == null) return;
|
||||
|
||||
ItemStack weaponDamager = equipDamager.getItemInMainHand();
|
||||
|
||||
for (ItemStack armor : EntityUtil.getArmor(victim)) {
|
||||
if (armor == null || armor.getType().isAir()) continue;
|
||||
|
||||
EnchantManager.getItemCustomEnchants(armor, CombatEnchant.class).forEach((combatEnchant, level) -> {
|
||||
combatEnchant.use(e, damager, victim, weaponDamager, level);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Bow Shooting Enchants
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantBowShoot(EntityShootBowEvent e) {
|
||||
LivingEntity shooter = e.getEntity();
|
||||
if (shooter.getEquipment() == null) return;
|
||||
|
||||
ItemStack bow = e.getBow();
|
||||
if (bow == null || bow.getType().isAir() || bow.getType() == Material.ENCHANTED_BOOK) return;
|
||||
|
||||
EnchantManager.getItemCustomEnchants(bow, BowEnchant.class).forEach((bowEnchant, level) -> {
|
||||
bowEnchant.use(e, shooter, bow, level);
|
||||
});
|
||||
|
||||
if (e.getProjectile() instanceof Projectile projectile) {
|
||||
EnchantManager.setArrowWeapon(projectile, bow);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Bow Damage Enchants
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantBowDamage(EntityDamageByEntityEvent e) {
|
||||
if (!(e.getEntity() instanceof LivingEntity victim)) return;
|
||||
if (!(e.getDamager() instanceof Projectile projectile)) return;
|
||||
if (!(projectile.getShooter() instanceof LivingEntity damager)) return;
|
||||
|
||||
ItemStack bow = EnchantManager.getArrowWeapon(projectile);
|
||||
if (bow == null || bow.getType().isAir() || bow.getType() == Material.ENCHANTED_BOOK) return;
|
||||
|
||||
EnchantManager.getItemCustomEnchants(bow, BowEnchant.class).forEach((bowEnchant, level) -> {
|
||||
bowEnchant.use(e, damager, victim, bow, level);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Bow Hit Land Enchants
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantBowHit(ProjectileHitEvent e) {
|
||||
Projectile projectile = e.getEntity();
|
||||
|
||||
ItemStack bow = EnchantManager.getArrowWeapon(projectile);
|
||||
if (bow == null || bow.getType().isAir() || bow.getType() == Material.ENCHANTED_BOOK) return;
|
||||
|
||||
EnchantManager.getItemCustomEnchants(bow, BowEnchant.class).forEach((bowEnchant, level) -> {
|
||||
bowEnchant.use(e, projectile, bow, level);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Interaction Related Enchants
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onEnchantInteract(PlayerInteractEvent e) {
|
||||
if (e.useInteractedBlock() == Result.DENY) return;
|
||||
if (e.useItemInHand() == Result.DENY) return;
|
||||
|
||||
ItemStack item = e.getItem();
|
||||
if (item == null || item.getType().isAir() || item.getType() == Material.ENCHANTED_BOOK) return;
|
||||
|
||||
Player player = e.getPlayer();
|
||||
EnchantManager.getItemCustomEnchants(item, InteractEnchant.class).forEach((interEnchant, level) -> {
|
||||
interEnchant.use(e, player, item, level);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Death Related Enchants
|
||||
// ---------------------------------------------------------------
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onEnchantDeath(EntityDeathEvent e) {
|
||||
LivingEntity dead = e.getEntity();
|
||||
for (ItemStack armor : EntityUtil.getArmor(dead)) {
|
||||
if (armor == null || armor.getType().isAir()) continue;
|
||||
|
||||
EnchantManager.getItemCustomEnchants(armor, DeathEnchant.class).forEach((deathEnchant, level) -> {
|
||||
deathEnchant.use(e, dead, level);
|
||||
});
|
||||
}
|
||||
|
||||
Player killer = dead.getKiller();
|
||||
if (killer == null) return;
|
||||
|
||||
ItemStack weapon = killer.getInventory().getItemInMainHand();
|
||||
if (weapon.getType().isAir() || weapon.getType() == Material.ENCHANTED_BOOK) return;
|
||||
|
||||
EnchantManager.getItemCustomEnchants(weapon, DeathEnchant.class).forEach((deathEnchant, level) -> {
|
||||
deathEnchant.use(e, dead, level);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle BlockBreak enchantments.
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onEnchantBlockBreak(BlockBreakEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
if (player.getGameMode() == GameMode.CREATIVE) return;
|
||||
|
||||
ItemStack tool = player.getInventory().getItemInMainHand();
|
||||
if (tool.getType().isAir() || tool.getType() == Material.ENCHANTED_BOOK) return;
|
||||
|
||||
EnchantManager.getItemCustomEnchants(tool, BlockBreakEnchant.class).forEach((blockEnchant, level) -> {
|
||||
blockEnchant.use(e, player, tool, level);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
package su.nightexpress.excellentenchants.manager.object;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.api.menu.*;
|
||||
import su.nexmedia.engine.utils.CollectionsUtil;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nexmedia.engine.utils.PDCUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.EnchantRegister;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class EnchantListGUI extends AbstractMenu<ExcellentEnchants> {
|
||||
|
||||
private final ItemStack enchantIcon;
|
||||
private final int[] enchantSlots;
|
||||
|
||||
private final NamespacedKey keyLevel;
|
||||
private final Map<String, Map<Integer, ItemStack>> iconCache;
|
||||
|
||||
public EnchantListGUI(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, JYML.loadOrExtract(plugin, "gui.enchants.yml"), "");
|
||||
this.keyLevel = new NamespacedKey(plugin, "list_display_level");
|
||||
this.iconCache = new HashMap<>();
|
||||
|
||||
this.enchantIcon = cfg.getItem("Enchantments.Icon");
|
||||
this.enchantSlots = cfg.getIntArray("Enchantments.Slots");
|
||||
|
||||
IMenuClick click = (p, type, e) -> {
|
||||
if (type instanceof MenuItemType type2) {
|
||||
switch (type2) {
|
||||
case PAGE_NEXT -> this.open(p, this.getPage(p) + 1);
|
||||
case PAGE_PREVIOUS -> this.open(p, this.getPage(p) - 1);
|
||||
case CLOSE -> p.closeInventory();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (String sId : cfg.getSection("Content")) {
|
||||
IMenuItem menuItem = cfg.getMenuItem("Content." + sId);
|
||||
|
||||
if (menuItem.getType() != null) {
|
||||
menuItem.setClick(click);
|
||||
}
|
||||
this.addItem(menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack getEnchantIcon(@NotNull ExcellentEnchant enchant, int level) {
|
||||
return this.iconCache.computeIfAbsent(enchant.getId(), k -> new HashMap<>()).computeIfAbsent(level, k -> this.buildEnchantIcon(enchant, level));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ItemStack buildEnchantIcon(@NotNull ExcellentEnchant enchant, int level) {
|
||||
ItemStack icon = new ItemStack(this.enchantIcon);
|
||||
|
||||
// Override the conflicts placeholder display to make it in a list.
|
||||
List<String> conflicts = enchant.getConflicts().isEmpty()
|
||||
? plugin.lang().Other_None.asList()
|
||||
: enchant.getConflicts().stream().filter(Objects::nonNull)
|
||||
.map(en -> plugin.lang().getEnchantment(en)).toList();
|
||||
|
||||
ItemUtil.replaceLore(icon, ExcellentEnchant.PLACEHOLDER_CONFLICTS, conflicts);
|
||||
ItemUtil.replace(icon, enchant.formatString(level));
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepare(@NotNull Player player, @NotNull Inventory inventory) {
|
||||
int page = this.getPage(player);
|
||||
int length = this.enchantSlots.length;
|
||||
List<ExcellentEnchant> list = new ArrayList<>(EnchantRegister.ENCHANT_LIST.stream().
|
||||
sorted(Comparator.comparing(ExcellentEnchant::getName)).toList());
|
||||
List<List<ExcellentEnchant>> split = CollectionsUtil.split(list, length);
|
||||
|
||||
int pages = split.size();
|
||||
if (pages < 1 || pages < page) list = Collections.emptyList();
|
||||
else list = split.get(page - 1);
|
||||
|
||||
int count = 0;
|
||||
for (ExcellentEnchant enchant : list) {
|
||||
ItemStack icon = this.getEnchantIcon(enchant, 1);
|
||||
PDCUtil.setData(icon, this.keyLevel, 1);
|
||||
|
||||
IMenuClick click = (p, type, e) -> {
|
||||
if (!e.isLeftClick()) return;
|
||||
|
||||
ItemStack itemClick = e.getCurrentItem();
|
||||
if (itemClick == null) return;
|
||||
|
||||
int levelHas = PDCUtil.getIntData(itemClick, this.keyLevel);
|
||||
if (levelHas == 0) return;
|
||||
|
||||
if (++levelHas > enchant.getMaxLevel()) levelHas = enchant.getStartLevel();
|
||||
itemClick = this.getEnchantIcon(enchant, levelHas);
|
||||
PDCUtil.setData(itemClick, this.keyLevel, levelHas);
|
||||
|
||||
e.setCurrentItem(itemClick);
|
||||
};
|
||||
|
||||
IMenuItem menuItem = new MenuItem(icon, this.enchantSlots[count++]);
|
||||
menuItem.setClick(click);
|
||||
this.addItem(player, menuItem);
|
||||
}
|
||||
this.setPage(player, page, pages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReady(@NotNull Player player, @NotNull Inventory inventory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelClick(@NotNull SlotType slotType, int slot) {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package su.nightexpress.excellentenchants.manager.object;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.manager.leveling.Scaler;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
|
||||
|
||||
public class EnchantScaler extends Scaler {
|
||||
|
||||
public EnchantScaler(@NotNull ExcellentEnchant enchant, @NotNull String path) {
|
||||
super(enchant.getConfig(), path, ExcellentEnchant.PLACEHOLDER_LEVEL, enchant.getStartLevel(), enchant.getMaxLevel());
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package su.nightexpress.excellentenchants.manager.object;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.utils.StringUtil;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.manager.type.ObtainType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class EnchantTier {
|
||||
|
||||
private final String id;
|
||||
private final int priority;
|
||||
private final String name;
|
||||
private final String color;
|
||||
private final Map<ObtainType, Double> chance;
|
||||
|
||||
private final Set<ExcellentEnchant> enchants;
|
||||
|
||||
public EnchantTier(@NotNull String id, int priority, @NotNull String name, @NotNull String color, @NotNull Map<ObtainType, Double> chance) {
|
||||
this.id = id.toLowerCase();
|
||||
this.priority = priority;
|
||||
this.name = StringUtil.color(name);
|
||||
this.color = StringUtil.color(color);
|
||||
this.chance = chance;
|
||||
this.enchants = new HashSet<>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getColor() {
|
||||
return this.color;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<ObtainType, Double> getChance() {
|
||||
return this.chance;
|
||||
}
|
||||
|
||||
public double getChance(@NotNull ObtainType obtainType) {
|
||||
return this.getChance().getOrDefault(obtainType, 0D);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<ExcellentEnchant> getEnchants() {
|
||||
return this.enchants;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<ExcellentEnchant> getEnchants(@NotNull ObtainType obtainType) {
|
||||
return this.getEnchants(obtainType, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<ExcellentEnchant> getEnchants(@NotNull ObtainType obtainType, @Nullable ItemStack item) {
|
||||
Set<ExcellentEnchant> set = this.getEnchants().stream()
|
||||
.filter(en -> en.getObtainChance(obtainType) > 0)
|
||||
.filter(en -> item == null || en.canEnchantItem(item)).collect(Collectors.toSet());
|
||||
set.removeIf(en -> obtainType == ObtainType.ENCHANTING && en.isTreasure());
|
||||
return set;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ExcellentEnchant getEnchant(@NotNull ObtainType obtainType) {
|
||||
return getEnchant(obtainType, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ExcellentEnchant getEnchant(@NotNull ObtainType obtainType, @Nullable ItemStack item) {
|
||||
Map<ExcellentEnchant, Double> map = this.getEnchants(obtainType).stream()
|
||||
.filter(en -> item == null || en.canEnchantItem(item))
|
||||
.collect(Collectors.toMap(k -> k, v -> v.getObtainChance(obtainType)));
|
||||
return map.isEmpty() ? null : Rnd.get(map);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package su.nightexpress.excellentenchants.manager.tasks;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.task.AbstractTask;
|
||||
import su.nexmedia.engine.utils.EntityUtil;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class AbstractEnchantPassiveTask extends AbstractTask<ExcellentEnchants> {
|
||||
|
||||
public AbstractEnchantPassiveTask(@NotNull ExcellentEnchants plugin, long interval, boolean async) {
|
||||
super(plugin, interval, async);
|
||||
}
|
||||
|
||||
protected abstract void apply(@NotNull LivingEntity entity, @NotNull ItemStack armor, @NotNull ItemMeta meta);
|
||||
|
||||
@Override
|
||||
public void action() {
|
||||
for (LivingEntity entity : this.getEntities()) {
|
||||
|
||||
List<ItemStack> list = new ArrayList<>(Arrays.asList(EntityUtil.getArmor(entity)));
|
||||
EntityEquipment equipment = entity.getEquipment();
|
||||
if (equipment != null && !ItemUtil.isArmor(equipment.getItemInMainHand())) {
|
||||
list.add(equipment.getItemInMainHand());
|
||||
}
|
||||
list.removeIf(armor -> armor == null || armor.getType().isAir() || armor.getType() == Material.ENCHANTED_BOOK);
|
||||
|
||||
for (ItemStack armor : list) {
|
||||
ItemMeta meta = armor.getItemMeta();
|
||||
if (meta == null) continue;
|
||||
|
||||
this.apply(entity, armor, meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Collection<@NotNull ? extends LivingEntity> getEntities() {
|
||||
Set<LivingEntity> list = new HashSet<>(plugin.getServer().getOnlinePlayers());
|
||||
|
||||
if (Config.ENCHANTMENTS_ENTITY_PASSIVE_FOR_MOBS) {
|
||||
plugin.getServer().getWorlds().forEach(world -> {
|
||||
list.addAll(world.getEntitiesByClass(LivingEntity.class));
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package su.nightexpress.excellentenchants.manager.tasks;
|
||||
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.task.AbstractTask;
|
||||
import su.nexmedia.engine.utils.EffectUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ArrowTrailsTask extends AbstractTask<ExcellentEnchants> {
|
||||
|
||||
private static final Map<Projectile, Set<Map.Entry<String, String>>> TRAILS_MAP = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
public ArrowTrailsTask(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, Config.TASKS_ARROW_TRAIL_TICKS_INTERVAL, true);
|
||||
TRAILS_MAP.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action() {
|
||||
TRAILS_MAP.keySet().removeIf(projectile -> !projectile.isValid() || projectile.isDead());
|
||||
|
||||
TRAILS_MAP.forEach((arrow, effects) -> {
|
||||
effects.forEach(entry -> {
|
||||
EffectUtil.playEffect(arrow.getLocation(), entry.getKey(), entry.getValue(), 0f, 0f, 0f, 0f, 10);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static void add(@NotNull Projectile projectile, @NotNull String particleName, @NotNull String particleData) {
|
||||
synchronized (TRAILS_MAP) {
|
||||
TRAILS_MAP.computeIfAbsent(projectile, list -> new HashSet<>()).add(new AbstractMap.SimpleEntry<>(particleName, particleData));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package su.nightexpress.excellentenchants.manager.tasks;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantPotionTemplate;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
|
||||
public class EnchantEffectPassiveTask extends AbstractEnchantPassiveTask {
|
||||
|
||||
public EnchantEffectPassiveTask(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, Config.TASKS_PASSIVE_ENCHANTS_TICKS_INTERVAL, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(@NotNull LivingEntity entity, @NotNull ItemStack armor, @NotNull ItemMeta meta) {
|
||||
meta.getEnchants().forEach((enchantment, level) -> {
|
||||
if (level < 1) return;
|
||||
if (!(enchantment instanceof PassiveEnchant passiveEnchant)) return;
|
||||
if (!(enchantment instanceof IEnchantPotionTemplate)) return;
|
||||
|
||||
passiveEnchant.use(entity, level);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package su.nightexpress.excellentenchants.manager.type;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
|
||||
public enum FitItemType {
|
||||
|
||||
HELMET, CHESTPLATE, LEGGINGS, BOOTS, ELYTRA,
|
||||
WEAPON, TOOL, ARMOR,
|
||||
SWORD, TRIDENT, AXE, BOW, CROSSBOW,
|
||||
HOE, PICKAXE, SHOVEL, FISHING_ROD;
|
||||
|
||||
@Nullable
|
||||
public static FitItemType getByEnchantmentTarget(@NotNull EnchantmentTarget target) {
|
||||
return switch (target) {
|
||||
case ARMOR -> ARMOR;
|
||||
case ARMOR_FEET -> BOOTS;
|
||||
case ARMOR_LEGS -> LEGGINGS;
|
||||
case ARMOR_TORSO -> CHESTPLATE;
|
||||
case ARMOR_HEAD -> HELMET;
|
||||
case WEAPON -> WEAPON;
|
||||
case TOOL -> TOOL;
|
||||
case BOW -> BOW;
|
||||
case FISHING_ROD -> FISHING_ROD;
|
||||
case TRIDENT -> TRIDENT;
|
||||
case CROSSBOW -> CROSSBOW;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public boolean isIncluded(@NotNull ItemStack item) {
|
||||
return switch (this) {
|
||||
case HELMET -> ItemUtil.isHelmet(item);
|
||||
case CHESTPLATE -> ItemUtil.isChestplate(item) || (Config.ENCHANTMENTS_ITEM_ELYTRA_AS_CHESTPLATE && ELYTRA.isIncluded(item));
|
||||
case LEGGINGS -> ItemUtil.isLeggings(item);
|
||||
case BOOTS -> ItemUtil.isBoots(item);
|
||||
case ELYTRA -> item.getType() == Material.ELYTRA;
|
||||
case WEAPON -> ItemUtil.isWeapon(item);
|
||||
case TOOL -> ItemUtil.isTool(item);
|
||||
case ARMOR -> ItemUtil.isArmor(item);
|
||||
case SWORD -> ItemUtil.isSword(item) || (Config.ENCHANTMENTS_ITEM_AXES_AS_SWORDS && AXE.isIncluded(item));
|
||||
case TRIDENT -> ItemUtil.isTrident(item);
|
||||
case AXE -> ItemUtil.isAxe(item);
|
||||
case BOW -> item.getType() == Material.BOW || (Config.ENCHANTMENTS_ITEM_CROSSBOWS_AS_BOWS && CROSSBOW.isIncluded(item));
|
||||
case CROSSBOW -> item.getType() == Material.CROSSBOW;
|
||||
case HOE -> ItemUtil.isHoe(item);
|
||||
case PICKAXE -> ItemUtil.isPickaxe(item);
|
||||
case SHOVEL -> ItemUtil.isShovel(item);
|
||||
case FISHING_ROD -> item.getType() == Material.FISHING_ROD;
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package su.nightexpress.excellentenchants.manager.type;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum ObtainType {
|
||||
|
||||
ENCHANTING("Enchanting_Table"),
|
||||
VILLAGER("Villagers"),
|
||||
LOOT_GENERATION("Loot_Generation"),
|
||||
FISHING("Fishing"),
|
||||
MOB_SPAWNING("Mob_Spawning");
|
||||
|
||||
private final String pathName;
|
||||
|
||||
ObtainType(@NotNull String pathName) {
|
||||
this.pathName = pathName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getPathName() {
|
||||
return pathName;
|
||||
}
|
||||
}
|
165
Core/src/main/resources/config.yml
Normal file
165
Core/src/main/resources/config.yml
Normal file
@ -0,0 +1,165 @@
|
||||
# Plugin engine settings.
|
||||
Plugin:
|
||||
# Name(s) for the main plugin command.
|
||||
Command_Aliases: excellentenchants,eenchants
|
||||
# Plugin language config.
|
||||
#
|
||||
# In 'lang' folder there are configs for different languages with a format like 'messages_code.yml',
|
||||
# where 'code' is the language code which you specify here.
|
||||
#
|
||||
# To create a new language config, simply copy the default one and rename it to your language code.
|
||||
Language: en
|
||||
# Plugin prefix name.
|
||||
# To change a prefix format, edit language config in '/NexEngine/lang'.
|
||||
Prefix: ExcellentEnchants
|
||||
|
||||
# General plugin settings.
|
||||
General:
|
||||
# Settings for the plugin tasks.
|
||||
Tasks:
|
||||
Arrow_Trails:
|
||||
# Defines the ticks interval (20 ticks = 1 second) for the arrow particle effect spawning.
|
||||
Ticks_Interval: 1
|
||||
Passive_Enchants:
|
||||
# Defines the ticks interval (20 ticks = 1 second) for the passive enchantment effects to trigger.
|
||||
Ticks_Interval: 100
|
||||
# Enchantment global settings.
|
||||
Enchantments:
|
||||
# List of disabled custom enchantments.
|
||||
# Use enchantment file names from the 'enchants' folder without the file extension.
|
||||
# For example, to disable 'Explosive Arrows' enchantment you have to add 'explosive_arrows' to this list.
|
||||
Disabled:
|
||||
- enchant_name
|
||||
- other_enchant
|
||||
# Here you can disable certain enchantments in certain worlds.
|
||||
Disabled_In_Worlds:
|
||||
# This is your world name with a list of disabled enchantments.
|
||||
# Enchantment names are the same as in the option above.
|
||||
# To disable all enchantments, use '*'.
|
||||
my_world:
|
||||
- '*'
|
||||
other_world:
|
||||
- 'enchant_name'
|
||||
- 'another_enchant'
|
||||
# Item settings.
|
||||
Item:
|
||||
# How many of custom enchantments the item can contain at the same time?
|
||||
Max_Custom_Enchants: 3
|
||||
# Set this to 'true' to make Sword enchantments apply on Axes.
|
||||
Axes_As_Swords: true
|
||||
# Set this to 'true' to make Bow enchantments apply on Crossbows.
|
||||
Crossbows_As_Bows: true
|
||||
# Set this to 'true' to make Chestplate enchantments apply on Elytras.
|
||||
Elytra_As_Chestplate: true
|
||||
# Non-player entity settings.
|
||||
Entity:
|
||||
# When enabled, enchantments with a passive effects (potion effects, regeneration, etc.)
|
||||
# will be applied to mobs as well (if they are wearing items with such enchantments).
|
||||
# Enabling this feature may cause performance issues.
|
||||
Passive_Enchants_Applied_To_Mobs: false
|
||||
# Enchantment description settings.
|
||||
Description:
|
||||
# When enabled, each custom enchantment will add a description in item lore.
|
||||
Enabled: true
|
||||
# Description format for the item lore.
|
||||
# Placeholders:
|
||||
# - %description% - Enchantment description.
|
||||
Format: '&8▸ %description%'
|
||||
# Settings to obtain enchants via Enchanting Table.
|
||||
Enchanting_Table:
|
||||
# Enable/Disable this way to obtain custom enchantments.
|
||||
Enabled: true
|
||||
Enchantments:
|
||||
# Max. amount of all (including vanilla) enchantments on the item, when no more enchantments will be added.
|
||||
Total_Maximum: 4
|
||||
# Chance that a custom enchantment will be added.
|
||||
Custom_Generation_Chance: 90.0
|
||||
# Min. amount of custom enchantments to be added.
|
||||
Custom_Minimum: 0
|
||||
# Max. amount of custom enchantments to be added.
|
||||
Custom_Maximum: 2
|
||||
# Settings to obtain enchantments via Villager Trades.
|
||||
Villagers:
|
||||
Enabled: true
|
||||
Enchantments:
|
||||
Total_Maximum: 4
|
||||
Custom_Generation_Chance: 70.0
|
||||
Custom_Minimum: 0
|
||||
Custom_Maximum: 2
|
||||
# Settings to obtain enchantments via Loot Chests in dungeons and other world's structures.
|
||||
Loot_Generation:
|
||||
Enabled: true
|
||||
Enchantments:
|
||||
Total_Maximum: 4
|
||||
Custom_Generation_Chance: 80.0
|
||||
Custom_Minimum: 0
|
||||
Custom_Maximum: 2
|
||||
# Settings to obtain enchantments via Fishing.
|
||||
Fishing:
|
||||
Enabled: true
|
||||
Enchantments:
|
||||
Total_Maximum: 4
|
||||
Custom_Generation_Chance: 70.0
|
||||
Custom_Minimum: 0
|
||||
Custom_Maximum: 2
|
||||
# Settings to generate enchantments on mob equipment on spawn.
|
||||
Mob_Spawning:
|
||||
Enabled: true
|
||||
Enchantments:
|
||||
Total_Maximum: 4
|
||||
Custom_Generation_Chance: 70.0
|
||||
Custom_Minimum: 0
|
||||
Custom_Maximum: 2
|
||||
|
||||
# Enchantment tiers.
|
||||
# You can create as many tiers as you want.
|
||||
Tiers:
|
||||
# Tier identifier. Must be unique.
|
||||
common:
|
||||
# Tier display name.
|
||||
Name: '&fCommon'
|
||||
# Tier color.
|
||||
Color: '&f'
|
||||
# Tier obtain chances.
|
||||
Obtain_Chance:
|
||||
ENCHANTING: 80.0
|
||||
VILLAGER: 80.0
|
||||
LOOT_GENERATION: 80.0
|
||||
FISHING: 80.0
|
||||
MOB_SPAWNING: 80.0
|
||||
rare:
|
||||
Name: '&aRare'
|
||||
Color: '&a'
|
||||
Obtain_Chance:
|
||||
ENCHANTING: 50.0
|
||||
VILLAGER: 50.0
|
||||
LOOT_GENERATION: 50.0
|
||||
FISHING: 50.0
|
||||
MOB_SPAWNING: 50.0
|
||||
exotic:
|
||||
Name: '&eExotic'
|
||||
Color: '&e'
|
||||
Obtain_Chance:
|
||||
ENCHANTING: 25.0
|
||||
VILLAGER: 25.0
|
||||
LOOT_GENERATION: 25.0
|
||||
FISHING: 25.0
|
||||
MOB_SPAWNING: 25.0
|
||||
legendary:
|
||||
Name: '&6Legendary'
|
||||
Color: '&6'
|
||||
Obtain_Chance:
|
||||
ENCHANTING: 10.0
|
||||
VILLAGER: 10.0
|
||||
LOOT_GENERATION: 10.0
|
||||
FISHING: 10.0
|
||||
MOB_SPAWNING: 10.0
|
||||
cursed:
|
||||
Name: '&cCursed'
|
||||
Color: '&c'
|
||||
Obtain_Chance:
|
||||
ENCHANTING: 7.0
|
||||
VILLAGER: 5.0
|
||||
LOOT_GENERATION: 7.0
|
||||
FISHING: 12.0
|
||||
MOB_SPAWNING: 0.0
|
31
Core/src/main/resources/enchants/aquaman.yml
Normal file
31
Core/src/main/resources/enchants/aquaman.yml
Normal file
@ -0,0 +1,31 @@
|
||||
Name: 'Aquaman'
|
||||
Tier: 'exotic'
|
||||
Description:
|
||||
- 'Grants %enchantment_potion_type% %enchantment_potion_level% effect that costs x1 %enchantment_cost_item%.'
|
||||
Is_Treasure: false
|
||||
Level:
|
||||
Min: 1
|
||||
Max: 1
|
||||
Anvil:
|
||||
Merge_Cost: '%enchantment_level%'
|
||||
Enchanting_Table:
|
||||
Level_By_Exp_Cost: '%enchantment_level% * 15.0'
|
||||
Chance: 20.0
|
||||
Villagers:
|
||||
Chance: 20.0
|
||||
Loot_Generation:
|
||||
Chance: 25.0
|
||||
Fishing:
|
||||
Chance: 30.0
|
||||
Mob_Spawning:
|
||||
Chance: 0.0
|
||||
Settings:
|
||||
Trigger_Chance: '100.0'
|
||||
Cost:
|
||||
Enabled: true
|
||||
Item:
|
||||
Material: PRISMARINE_SHARD
|
||||
Amount: 1
|
||||
Potion_Effect:
|
||||
Level: '1'
|
||||
Duration: '25.0'
|
34
Core/src/main/resources/enchants/bane_of_netherspawn.yml
Normal file
34
Core/src/main/resources/enchants/bane_of_netherspawn.yml
Normal file
@ -0,0 +1,34 @@
|
||||
Name: Bane of Netherspawn
|
||||
Tier: common
|
||||
Description:
|
||||
- '%enchantment_trigger_chance%% chance to inflict %enchantment_damage% more damage to Nether mobs.'
|
||||
Is_Treasure: false
|
||||
Level:
|
||||
Min: 1
|
||||
Max: 5
|
||||
Anvil:
|
||||
Merge_Cost: '%enchantment_level%'
|
||||
Fishing:
|
||||
Chance: 25.0
|
||||
Enchanting_Table:
|
||||
Level_By_Exp_Cost: '6 * %enchantment_level%'
|
||||
Chance: 80.0
|
||||
Villagers:
|
||||
Chance: 80.0
|
||||
Loot_Generation:
|
||||
Chance: 80.0
|
||||
Mob_Spawning:
|
||||
Chance: 50.0
|
||||
Settings:
|
||||
Trigger_Chance: '100.0'
|
||||
Cost:
|
||||
Enabled: false
|
||||
Item:
|
||||
Material: AIR
|
||||
Amount: 1
|
||||
Particle:
|
||||
Name: 'SMOKE_NORMAL'
|
||||
Data: ''
|
||||
Damage:
|
||||
As_Modifier: false
|
||||
Formula: '0.5 * %enchantment_level%'
|
31
Core/src/main/resources/enchants/blast_mining.yml
Normal file
31
Core/src/main/resources/enchants/blast_mining.yml
Normal file
@ -0,0 +1,31 @@
|
||||
Is_Treasure: false
|
||||
Name: Blast Mining
|
||||
Tier: legendary
|
||||
Description:
|
||||
- '%enchantment_trigger_chance%% chance to mine blocks by x%enchantment_explosion_power% power explosion.'
|
||||
Level:
|
||||
Min: 1
|
||||
Max: 5
|
||||
Anvil:
|
||||
Merge_Cost: '%enchantment_level%'
|
||||
Fishing:
|
||||
Chance: 5.0
|
||||
Enchanting_Table:
|
||||
Level_By_Exp_Cost: '6.0 * %enchantment_level%'
|
||||
Chance: 10.0
|
||||
Villagers:
|
||||
Chance: 10.0
|
||||
Loot_Generation:
|
||||
Chance: 20.0
|
||||
Mob_Spawning:
|
||||
Chance: 0.0
|
||||
Settings:
|
||||
Trigger_Chance: '20.0 * %enchantment_level%'
|
||||
Min_Block_Strength: '1.5 - %enchantment_level% / 10'
|
||||
Cost:
|
||||
Enabled: false
|
||||
Item:
|
||||
Material: AIR
|
||||
Amount: 1
|
||||
Explosion:
|
||||
Power: '3.0 + (%enchantment_level% - 1.0 * 0.25)'
|
34
Core/src/main/resources/enchants/blindness.yml
Normal file
34
Core/src/main/resources/enchants/blindness.yml
Normal file
@ -0,0 +1,34 @@
|
||||
Is_Treasure: false
|
||||
Name: Blindness
|
||||
Tier: common
|
||||
Description:
|
||||
- '%enchantment_trigger_chance%% chance to apply %enchantment_potion_type% %enchantment_potion_level% for %enchantment_potion_duration%s. on hit.'
|
||||
Level:
|
||||
Min: 1
|
||||
Max: 3
|
||||
Anvil:
|
||||
Merge_Cost: '%enchantment_level%'
|
||||
Fishing:
|
||||
Chance: 60.0
|
||||
Enchanting_Table:
|
||||
Level_By_Exp_Cost: '9 * %enchantment_level%'
|
||||
Chance: 60.0
|
||||
Villagers:
|
||||
Chance: 60.0
|
||||
Loot_Generation:
|
||||
Chance: 60.0
|
||||
Mob_Spawning:
|
||||
Chance: 30.0
|
||||
Settings:
|
||||
Trigger_Chance: '15.0 + %enchantment_level% * 3'
|
||||
Cost:
|
||||
Enabled: false
|
||||
Item:
|
||||
Material: AIR
|
||||
Amount: 1
|
||||
Potion_Effect:
|
||||
Duration: '3.5 + %enchantment_level%'
|
||||
Level: '%enchantment_level%'
|
||||
Particle:
|
||||
Name: SMOKE_NORMAL
|
||||
Data: ''
|
29
Core/src/main/resources/enchants/bomber.yml
Normal file
29
Core/src/main/resources/enchants/bomber.yml
Normal file
@ -0,0 +1,29 @@
|
||||
Is_Treasure: false
|
||||
Name: Bomber
|
||||
Tier: exotic
|
||||
Description:
|
||||
- '%enchantment_trigger_chance%% chance to launch TNT that explodes in %enchantment_fuse_ticks%s.'
|
||||
Level:
|
||||
Min: 1
|
||||
Max: 3
|
||||
Anvil:
|
||||
Merge_Cost: '%enchantment_level%'
|
||||
Fishing:
|
||||
Chance: 20.0
|
||||
Enchanting_Table:
|
||||
Level_By_Exp_Cost: '9 * %enchantment_level%'
|
||||
Chance: 20.0
|
||||
Villagers:
|
||||
Chance: 20.0
|
||||
Loot_Generation:
|
||||
Chance: 20.0
|
||||
Mob_Spawning:
|
||||
Chance: 5.0
|
||||
Settings:
|
||||
Trigger_Chance: '4.0 * %enchantment_level%'
|
||||
Cost:
|
||||
Enabled: false
|
||||
Item:
|
||||
Material: TNT
|
||||
Amount: 1
|
||||
Fuse_Ticks: '100 - %enchantment_level% * 10'
|
30
Core/src/main/resources/enchants/bunny_hop.yml
Normal file
30
Core/src/main/resources/enchants/bunny_hop.yml
Normal file
@ -0,0 +1,30 @@
|
||||
Is_Treasure: false
|
||||
Name: Bunny Hop
|
||||
Tier: common
|
||||
Description:
|
||||
- 'Grants permanent %enchantment_potion_type% %enchantment_potion_level%.'
|
||||
Level:
|
||||
Min: 1
|
||||
Max: 3
|
||||
Anvil:
|
||||
Merge_Cost: '%enchantment_level%'
|
||||
Fishing:
|
||||
Chance: 50.0
|
||||
Enchanting_Table:
|
||||
Level_By_Exp_Cost: '9 * %enchantment_level%'
|
||||
Chance: 50.0
|
||||
Villagers:
|
||||
Chance: 50.0
|
||||
Loot_Generation:
|
||||
Chance: 50.0
|
||||
Mob_Spawning:
|
||||
Chance: 25.0
|
||||
Settings:
|
||||
Trigger_Chance: '100.0'
|
||||
Cost:
|
||||
Enabled: false
|
||||
Item:
|
||||
Material: RABBIT_FOOT
|
||||
Potion_Effect:
|
||||
Duration: '25.0'
|
||||
Level: '%enchantment_level%'
|
31
Core/src/main/resources/enchants/cold_steel.yml
Normal file
31
Core/src/main/resources/enchants/cold_steel.yml
Normal file
@ -0,0 +1,31 @@
|
||||
Is_Treasure: false
|
||||
Name: Cold Steel
|
||||
Tier: rare
|
||||
Description:
|
||||
- '%enchantment_trigger_chance%% chance to apply %enchantment_potion_type% %enchantment_potion_level% for %enchantment_potion_duration%s. to attacker.'
|
||||
Level:
|
||||
Min: 1
|
||||
Max: 3
|
||||
Anvil:
|
||||
Merge_Cost: '%enchantment_level%'
|
||||
Fishing:
|
||||
Chance: 50.0
|
||||
Enchanting_Table:
|
||||
Level_By_Exp_Cost: '9 * %enchantment_level%'
|
||||
Chance: 50.0
|
||||
Villagers:
|
||||
Chance: 50.0
|
||||
Loot_Generation:
|
||||
Chance: 50.0
|
||||
Mob_Spawning:
|
||||
Chance: 30.0
|
||||
Settings:
|
||||
Trigger_Chance: '60.0 + %enchantment_level% * 5'
|
||||
Cost:
|
||||
Enabled: false
|
||||
Item:
|
||||
Material: AIR
|
||||
Amount: 1
|
||||
Potion_Effect:
|
||||
Duration: '4.0 + %enchantment_level%'
|
||||
Level: '%enchantment_level%'
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user