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