upload
This commit is contained in:
commit
87358cddb4
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/.idea/
|
||||
/target/
|
||||
/pom.xml.versionsBackup
|
||||
/Core/target/
|
||||
/Core/pom.xml.versionsBackup
|
||||
/NMS/target/
|
||||
/NMS/pom.xml.versionsBackup
|
||||
/V1_18_R2/target/
|
||||
/V1_18_R2/pom.xml.versionsBackup
|
||||
/V1_19_R3/target/
|
||||
/V1_19_R3/pom.xml.versionsBackup
|
||||
/V1_20_R1/target/
|
||||
/V1_20_R1/pom.xml.versionsBackup
|
||||
/V1_20_R2/target/
|
||||
/V1_20_R2/pom.xml.versionsBackup
|
||||
/V1_20_R3/target/
|
||||
/V1_20_R3/pom.xml.versionsBackup
|
||||
/API/target/
|
||||
/API/pom.xml.versionsBackup
|
19
API/pom.xml
Normal file
19
API/pom.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?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.6.5</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>API</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -0,0 +1,94 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface IEnchantment extends Keyed {
|
||||
|
||||
boolean isAvailableToUse(@NotNull LivingEntity entity);
|
||||
|
||||
@NotNull JYML getConfig();
|
||||
|
||||
@NotNull String getId();
|
||||
|
||||
@NotNull String getDisplayName();
|
||||
|
||||
@NotNull String getNameFormatted(int level);
|
||||
|
||||
@NotNull String getNameFormatted(int level, int charges);
|
||||
|
||||
@NotNull List<String> getDescription();
|
||||
|
||||
@NotNull List<String> getDescription(int level);
|
||||
|
||||
@NotNull Set<String> getConflicts();
|
||||
|
||||
@NotNull ITier getTier();
|
||||
|
||||
@NotNull EnchantmentTarget getCategory();
|
||||
|
||||
ItemCategory[] getFitItemTypes();
|
||||
|
||||
int getMaxLevel();
|
||||
|
||||
int getStartLevel();
|
||||
|
||||
int getLevelByEnchantCost(int expLevel);
|
||||
|
||||
double getObtainChance(@NotNull ObtainType obtainType);
|
||||
|
||||
int getObtainLevelMin(@NotNull ObtainType obtainType);
|
||||
|
||||
int getObtainLevelMax(@NotNull ObtainType obtainType);
|
||||
|
||||
int generateLevel(@NotNull ObtainType obtainType);
|
||||
|
||||
int getAnvilMergeCost(int level);
|
||||
|
||||
//@Deprecated
|
||||
//boolean conflictsWith(@NotNull Enchantment enchantment);
|
||||
|
||||
boolean checkEnchantCategory(@NotNull ItemStack item);
|
||||
|
||||
boolean checkItemCategory(@NotNull ItemStack item);
|
||||
|
||||
boolean isCurse();
|
||||
|
||||
boolean isTreasure();
|
||||
|
||||
boolean isTradeable();
|
||||
|
||||
boolean isDiscoverable();
|
||||
|
||||
boolean isChargesEnabled();
|
||||
|
||||
int getChargesMax(int level);
|
||||
|
||||
int getChargesConsumeAmount(int level);
|
||||
|
||||
int getChargesRechargeAmount(int level);
|
||||
|
||||
@NotNull ItemStack getChargesFuel();
|
||||
|
||||
boolean isChargesFuel(@NotNull ItemStack item);
|
||||
|
||||
int getCharges(@NotNull ItemStack item);
|
||||
|
||||
boolean isFullOfCharges(@NotNull ItemStack item);
|
||||
|
||||
boolean isOutOfCharges(@NotNull ItemStack item);
|
||||
|
||||
void consumeCharges(@NotNull ItemStack item, int level);
|
||||
|
||||
void consumeChargesNoUpdate(@NotNull ItemStack item, int level);
|
||||
|
||||
EquipmentSlot[] getSlots();
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.placeholder.Placeholder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ITier extends Placeholder {
|
||||
|
||||
@NotNull String getId();
|
||||
|
||||
int getPriority();
|
||||
|
||||
@NotNull String getName();
|
||||
|
||||
@NotNull String getColor();
|
||||
|
||||
@NotNull Map<ObtainType, Double> getChance();
|
||||
|
||||
double getChance(@NotNull ObtainType obtainType);
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public enum ItemCategory {
|
||||
|
||||
HELMET(ItemUtil::isHelmet),
|
||||
CHESTPLATE(ItemUtil::isChestplate),
|
||||
LEGGINGS(ItemUtil::isLeggings),
|
||||
BOOTS(ItemUtil::isBoots),
|
||||
ELYTRA(item -> item.getType() == Material.ELYTRA),
|
||||
|
||||
SWORD(ItemUtil::isSword),
|
||||
TRIDENT(ItemUtil::isTrident),
|
||||
AXE(ItemUtil::isAxe),
|
||||
BOW(item -> item.getType() == Material.BOW),
|
||||
CROSSBOW(item -> item.getType() == Material.CROSSBOW),
|
||||
HOE(ItemUtil::isHoe),
|
||||
PICKAXE(ItemUtil::isPickaxe),
|
||||
SHOVEL(ItemUtil::isShovel),
|
||||
FISHING_ROD(ItemUtil::isFishingRod),
|
||||
|
||||
//@Deprecated WEAPON(item -> SWORD.isIncluded(item) || TRIDENT.isIncluded(item)),
|
||||
TOOL(ItemUtil::isTool),
|
||||
//@Deprecated ARMOR(ItemUtil::isArmor),
|
||||
//UNIVERSAL(item -> WEAPON.isIncluded(item) || TOOL.isIncluded(item) || ARMOR.isIncluded(item)),
|
||||
;
|
||||
|
||||
private Predicate<ItemStack> predicate;
|
||||
|
||||
ItemCategory(@NotNull Predicate<ItemStack> predicate) {
|
||||
this.setPredicate(predicate);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Predicate<ItemStack> getPredicate() {
|
||||
return predicate;
|
||||
}
|
||||
|
||||
public void setPredicate(@NotNull Predicate<ItemStack> predicate) {
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void patchPredicate(@NotNull Predicate<ItemStack> extra) {
|
||||
//this.setPredicate(item -> this.getPredicate().test(item) || (extra.test(item)));
|
||||
}
|
||||
|
||||
/*public EquipmentSlot[] getSlots() {
|
||||
return switch (this) {
|
||||
case BOW, CROSSBOW, TRIDENT, FISHING_ROD, WEAPON, TOOL, HOE, PICKAXE, AXE, SWORD, SHOVEL ->
|
||||
new EquipmentSlot[]{EquipmentSlot.HAND};
|
||||
case HELMET -> new EquipmentSlot[]{EquipmentSlot.HEAD};
|
||||
case CHESTPLATE, ELYTRA -> new EquipmentSlot[]{EquipmentSlot.CHEST};
|
||||
case LEGGINGS -> new EquipmentSlot[]{EquipmentSlot.LEGS};
|
||||
case BOOTS -> new EquipmentSlot[]{EquipmentSlot.FEET};
|
||||
case ARMOR -> new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
|
||||
case UNIVERSAL -> new EquipmentSlot[]{EquipmentSlot.HAND, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantmentTarget getEnchantmentTarget() {
|
||||
return switch (this) {
|
||||
case ARMOR -> EnchantmentTarget.ARMOR;
|
||||
case BOOTS -> EnchantmentTarget.ARMOR_FEET;
|
||||
case LEGGINGS -> EnchantmentTarget.ARMOR_LEGS;
|
||||
case CHESTPLATE, ELYTRA -> EnchantmentTarget.ARMOR_TORSO;
|
||||
case HELMET -> EnchantmentTarget.ARMOR_HEAD;
|
||||
case WEAPON, SWORD -> EnchantmentTarget.WEAPON;
|
||||
case TOOL, AXE, HOE, SHOVEL, PICKAXE -> EnchantmentTarget.TOOL;
|
||||
case BOW -> EnchantmentTarget.BOW;
|
||||
case FISHING_ROD -> EnchantmentTarget.FISHING_ROD;
|
||||
case TRIDENT -> EnchantmentTarget.TRIDENT;
|
||||
case CROSSBOW -> EnchantmentTarget.CROSSBOW;
|
||||
case UNIVERSAL -> EnchantmentTarget.WEARABLE;
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FitItemType getByEnchantmentTarget(@NotNull EnchantmentTarget target) {
|
||||
return switch (target) {
|
||||
case ARMOR -> ARMOR;
|
||||
case ARMOR_FEET -> BOOTS;
|
||||
case ARMOR_LEGS -> LEGGINGS;
|
||||
case ARMOR_TORSO -> CHESTPLATE;
|
||||
case ARMOR_HEAD -> HELMET;
|
||||
case WEAPON -> WEAPON;
|
||||
case TOOL -> TOOL;
|
||||
case BOW -> BOW;
|
||||
case FISHING_ROD -> FISHING_ROD;
|
||||
case TRIDENT -> TRIDENT;
|
||||
case CROSSBOW -> CROSSBOW;
|
||||
case BREAKABLE, WEARABLE -> UNIVERSAL;
|
||||
default -> throw new IllegalStateException("Unexpected value: " + target);
|
||||
};
|
||||
}*/
|
||||
|
||||
public boolean isIncluded(@NotNull ItemStack item) {
|
||||
return this.getPredicate().test(item);
|
||||
|
||||
/*return switch (this) {
|
||||
case UNIVERSAL -> ARMOR.isIncluded(item) || WEAPON.isIncluded(item) || TOOL.isIncluded(item) || BOW.isIncluded(item) || FISHING_ROD.isIncluded(item) || ELYTRA.isIncluded(item);
|
||||
case HELMET -> ItemUtil.isHelmet(item);
|
||||
case CHESTPLATE -> ItemUtil.isChestplate(item) || (Config.ENCHANTMENTS_ITEM_CHESTPLATE_ENCHANTS_TO_ELYTRA.get() && ELYTRA.isIncluded(item));
|
||||
case LEGGINGS -> ItemUtil.isLeggings(item);
|
||||
case BOOTS -> ItemUtil.isBoots(item);
|
||||
case ELYTRA -> item.getType() == Material.ELYTRA;
|
||||
case WEAPON -> SWORD.isIncluded(item) || ItemUtil.isTrident(item);
|
||||
case TOOL -> ItemUtil.isTool(item);
|
||||
case ARMOR -> ItemUtil.isArmor(item);
|
||||
case SWORD -> ItemUtil.isSword(item) || (Config.ENCHANTMENTS_ITEM_SWORD_ENCHANTS_TO_AXES.get() && AXE.isIncluded(item));
|
||||
case TRIDENT -> ItemUtil.isTrident(item);
|
||||
case AXE -> ItemUtil.isAxe(item);
|
||||
case BOW -> item.getType() == Material.BOW || (Config.ENCHANTMENTS_ITEM_BOW_ENCHANTS_TO_CROSSBOW.get() && CROSSBOW.isIncluded(item));
|
||||
case CROSSBOW -> item.getType() == Material.CROSSBOW;
|
||||
case HOE -> ItemUtil.isHoe(item);
|
||||
case PICKAXE -> ItemUtil.isPickaxe(item);
|
||||
case SHOVEL -> ItemUtil.isShovel(item);
|
||||
case FISHING_ROD -> item.getType() == Material.FISHING_ROD;
|
||||
};*/
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
public enum Rarity {
|
||||
|
||||
COMMON(10),
|
||||
UNCOMMON(5),
|
||||
RARE(2),
|
||||
VERY_RARE(1);
|
||||
|
||||
private final int weight;
|
||||
|
||||
Rarity(int weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return this.weight;
|
||||
}
|
||||
}
|
154
Core/pom.xml
Normal file
154
Core/pom.xml
Normal file
@ -0,0 +1,154 @@
|
||||
<?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.6.5</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>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>placeholderapi</id>
|
||||
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>lumine-repo</id>
|
||||
<url>https://mvn.lumine.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>lumine-snapshot</id>
|
||||
<url>http://mvn.lumine.io/repository/maven-snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.20.4-R0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.neatmonster</groupId>
|
||||
<artifactId>nocheatplus</artifactId>
|
||||
<version>3.16.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.lumine</groupId>
|
||||
<artifactId>Mythic-Dist</artifactId>
|
||||
<version>5.0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>API</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>NMS</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>V1_18_R2</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>V1_19_R3</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>V1_20_R1</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>V1_20_R2</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>su.nightexpress.excellentenchants</groupId>
|
||||
<artifactId>V1_20_R3</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</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>
|
||||
<!-- Java 16 Fix -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>9.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-commons</artifactId>
|
||||
<version>9.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<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,172 @@
|
||||
package su.nightexpress.excellentenchants;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.NexPlugin;
|
||||
import su.nexmedia.engine.Version;
|
||||
import su.nexmedia.engine.api.command.GeneralCommand;
|
||||
import su.nexmedia.engine.command.list.ReloadSubCommand;
|
||||
import su.nexmedia.engine.utils.EngineUtils;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
|
||||
import su.nightexpress.excellentenchants.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.enchantment.EnchantManager;
|
||||
import su.nightexpress.excellentenchants.enchantment.EnchantPopulator;
|
||||
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
|
||||
import su.nightexpress.excellentenchants.hook.HookId;
|
||||
import su.nightexpress.excellentenchants.hook.impl.PlaceholderHook;
|
||||
import su.nightexpress.excellentenchants.hook.impl.ProtocolHook;
|
||||
import su.nightexpress.excellentenchants.nms.EnchantNMS;
|
||||
import su.nightexpress.excellentenchants.nms.v1_18_R2.V1_18_R2;
|
||||
import su.nightexpress.excellentenchants.nms.v1_19_R3.V1_19_R3;
|
||||
import su.nightexpress.excellentenchants.nms.v1_20_R1.V1_20_R1;
|
||||
import su.nightexpress.excellentenchants.nms.v1_20_R2.V1_20_R2;
|
||||
import su.nightexpress.excellentenchants.nms.v1_20_R3.V1_20_R3;
|
||||
import su.nightexpress.excellentenchants.tier.TierManager;
|
||||
|
||||
public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
|
||||
|
||||
// TODO Config option to use minecraft internal enchanting population
|
||||
// TODO Custom name format for curse enchants
|
||||
// TODO Custom name format for treasure enchants
|
||||
|
||||
private EnchantRegistry registry;
|
||||
private EnchantManager enchantManager;
|
||||
private EnchantNMS enchantNMS;
|
||||
private TierManager tierManager;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected ExcellentEnchants getSelf() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
super.onLoad();
|
||||
|
||||
//this.updateFitItemTypes();
|
||||
this.registry = new EnchantRegistry(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
if (!this.setNMS()) {
|
||||
this.error("Unsupported server version!");
|
||||
this.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.tierManager = new TierManager(this);
|
||||
this.tierManager.setup();
|
||||
|
||||
this.registry.setup();
|
||||
|
||||
this.enchantManager = new EnchantManager(this);
|
||||
this.enchantManager.setup();
|
||||
|
||||
if (Config.ENCHANTMENTS_DISPLAY_MODE.get() == 2) {
|
||||
if (EngineUtils.hasPlugin(HookId.PROTOCOL_LIB)) {
|
||||
ProtocolHook.setup();
|
||||
}
|
||||
else {
|
||||
this.warn(HookId.PROTOCOL_LIB + " is not installed. Set display mode to Plain lore.");
|
||||
Config.ENCHANTMENTS_DISPLAY_MODE.set(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
if (this.enchantManager != null) {
|
||||
this.enchantManager.shutdown();
|
||||
this.enchantManager = null;
|
||||
}
|
||||
if (this.tierManager != null) {
|
||||
this.tierManager.shutdown();
|
||||
this.tierManager = null;
|
||||
}
|
||||
if (EngineUtils.hasPlaceholderAPI()) {
|
||||
PlaceholderHook.shutdown();
|
||||
}
|
||||
this.registry.shutdown();
|
||||
}
|
||||
|
||||
private boolean setNMS() {
|
||||
this.enchantNMS = switch (Version.getCurrent()) {
|
||||
case V1_18_R2 -> new V1_18_R2();
|
||||
case V1_19_R3 -> new V1_19_R3();
|
||||
case V1_20_R1 -> new V1_20_R1();
|
||||
case V1_20_R2 -> new V1_20_R2();
|
||||
case V1_20_R3 -> new V1_20_R3();
|
||||
default -> null;
|
||||
};
|
||||
return this.enchantNMS != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadConfig() {
|
||||
this.getConfig().initializeOptions(Config.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadLang() {
|
||||
this.getLangManager().loadMissing(Lang.class);
|
||||
this.getLangManager().loadEnum(ItemCategory.class);
|
||||
this.getLangManager().loadEnum(EnchantmentTarget.class);
|
||||
this.getLangManager().loadEnum(ObtainType.class);
|
||||
this.getLang().saveChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands(@NotNull GeneralCommand<ExcellentEnchants> mainCommand) {
|
||||
mainCommand.addChildren(new BookCommand(this));
|
||||
mainCommand.addChildren(new EnchantCommand(this));
|
||||
mainCommand.addChildren(new ListCommand(this));
|
||||
mainCommand.addChildren(new TierbookCommand(this));
|
||||
mainCommand.addChildren(new ReloadSubCommand<>(this, Perms.COMMAND_RELOAD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerHooks() {
|
||||
if (EngineUtils.hasPlaceholderAPI()) {
|
||||
PlaceholderHook.setup(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPermissions() {
|
||||
this.registerPermissions(Perms.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantPopulator createPopulator(@NotNull ItemStack item, @NotNull ObtainType obtainType) {
|
||||
return new EnchantPopulator(this, item, obtainType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TierManager getTierManager() {
|
||||
return tierManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantRegistry getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantManager getEnchantManager() {
|
||||
return this.enchantManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantNMS getEnchantNMS() {
|
||||
return enchantNMS;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package su.nightexpress.excellentenchants;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
|
||||
import su.nightexpress.excellentenchants.tier.TierManager;
|
||||
|
||||
public class ExcellentEnchantsAPI {
|
||||
|
||||
public static final ExcellentEnchants PLUGIN = ExcellentEnchants.getPlugin(ExcellentEnchants.class);
|
||||
|
||||
@NotNull
|
||||
public static EnchantManager getEnchantManager() {
|
||||
return PLUGIN.getEnchantManager();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static TierManager getTierManager() {
|
||||
return PLUGIN.getTierManager();
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package su.nightexpress.excellentenchants;
|
||||
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import su.nexmedia.engine.api.server.JPermission;
|
||||
|
||||
public class Perms {
|
||||
|
||||
private static final String PREFIX = "excellentenchants.";
|
||||
private static final String PREFIX_COMMAND = PREFIX + "command.";
|
||||
|
||||
public static final JPermission PLUGIN = new JPermission(PREFIX + Placeholders.WILDCARD, "Access to all the plugin functions.");
|
||||
public static final JPermission COMMAND = new JPermission(PREFIX_COMMAND + Placeholders.WILDCARD, "Access to all the plugin commands.");
|
||||
|
||||
public static final JPermission COMMAND_BOOK = new JPermission(PREFIX_COMMAND + "book", "Allows to use '/eenchants book' command.");
|
||||
public static final JPermission COMMAND_ENCHANT = new JPermission(PREFIX_COMMAND + "enchant", "Allows to use '/eenchants enchant' command.");
|
||||
public static final JPermission COMMAND_LIST = new JPermission(PREFIX_COMMAND + "list", "Allows to use '/eenchants list' command.", PermissionDefault.TRUE);
|
||||
public static final JPermission COMMAND_TIERBOOK = new JPermission(PREFIX_COMMAND + "tierbook", "Allows to use '/eenchants tierbook' command.");
|
||||
public static final JPermission COMMAND_RELOAD = new JPermission(PREFIX_COMMAND + "reload", "Allows to use '/eenchants reload' command.");
|
||||
|
||||
static {
|
||||
PLUGIN.addChildren(COMMAND);
|
||||
|
||||
COMMAND.addChildren(COMMAND_BOOK, COMMAND_ENCHANT, COMMAND_LIST, COMMAND_RELOAD, COMMAND_TIERBOOK);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.151.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* su.nexmedia.engine.utils.Placeholders
|
||||
*/
|
||||
package su.nightexpress.excellentenchants;
|
||||
|
||||
public class Placeholders
|
||||
extends su.nexmedia.engine.utils.Placeholders {
|
||||
public static final String URL_WIKI = "https://github.com/nulli0n/ExcellentEnchants-spigot/wiki/";
|
||||
public static final String URL_PLACEHOLDERS = "https://github.com/nulli0n/ExcellentEnchants-spigot/wiki/Internal-Placeholders";
|
||||
public static final String URL_ENGINE_SCALER = "https://github.com/nulli0n/NexEngine-spigot/wiki/Configuration-Tips#scalable-sections";
|
||||
public static final String URL_ENGINE_ITEMS = "https://github.com/nulli0n/NexEngine-spigot/wiki/Configuration-Tips#item-sections";
|
||||
public static final String GENERIC_TYPE = "%type%";
|
||||
public static final String GENERIC_NAME = "%name%";
|
||||
public static final String GENERIC_ITEM = "%item%";
|
||||
public static final String GENERIC_LEVEL = "%level%";
|
||||
public static final String GENERIC_AMOUNT = "%amount%";
|
||||
public static final String GENERIC_DESCRIPTION = "%description%";
|
||||
public static final String GENERIC_ENCHANT = "%enchant%";
|
||||
public static final String ENCHANTMENT_CHANCE = "%enchantment_trigger_chance%";
|
||||
public static final String ENCHANTMENT_INTERVAL = "%enchantment_trigger_interval%";
|
||||
public static final String ENCHANTMENT_POTION_LEVEL = "%enchantment_potion_level%";
|
||||
public static final String ENCHANTMENT_POTION_DURATION = "%enchantment_potion_duration%";
|
||||
public static final String ENCHANTMENT_POTION_TYPE = "%enchantment_potion_type%";
|
||||
public static final String ENCHANTMENT_ID = "%enchantment_id%";
|
||||
public static final String ENCHANTMENT_NAME = "%enchantment_name%";
|
||||
public static final String ENCHANTMENT_NAME_FORMATTED = "%enchantment_name_formatted%";
|
||||
public static final String ENCHANTMENT_DESCRIPTION = "%enchantment_description%";
|
||||
public static final String ENCHANTMENT_LEVEL = "%enchantment_level%";
|
||||
public static final String ENCHANTMENT_LEVEL_MIN = "%enchantment_level_min%";
|
||||
public static final String ENCHANTMENT_LEVEL_MAX = "%enchantment_level_max%";
|
||||
public static final String ENCHANTMENT_TIER = "%enchantment_tier%";
|
||||
public static final String ENCHANTMENT_TIER_COLOR = "%enchantment_tier_color%";
|
||||
public static final String ENCHANTMENT_FIT_ITEM_TYPES = "%enchantment_fit_item_types%";
|
||||
public static final String ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING = "%enchantment_obtain_chance_enchanting%";
|
||||
public static final String ENCHANTMENT_OBTAIN_CHANCE_VILLAGER = "%enchantment_obtain_chance_villager%";
|
||||
public static final String ENCHANTMENT_OBTAIN_CHANCE_LOOT_GENERATION = "%enchantment_obtain_chance_loot_generation%";
|
||||
public static final String ENCHANTMENT_OBTAIN_CHANCE_FISHING = "%enchantment_obtain_chance_fishing%";
|
||||
public static final String ENCHANTMENT_OBTAIN_CHANCE_MOB_SPAWNING = "%enchantment_obtain_chance_mob_spawning%";
|
||||
public static final String ENCHANTMENT_CHARGES_MAX_AMOUNT = "%enchantment_charges_max_amount%";
|
||||
public static final String ENCHANTMENT_CHARGES_CONSUME_AMOUNT = "%enchantment_charges_consume_amount%";
|
||||
public static final String ENCHANTMENT_CHARGES_RECHARGE_AMOUNT = "%enchantment_charges_recharge_amount%";
|
||||
public static final String ENCHANTMENT_CHARGES_FUEL_ITEM = "%enchantment_charges_fuel_item%";
|
||||
public static final String TIER_ID = "%tier_id%";
|
||||
public static final String TIER_NAME = "%tier_name%";
|
||||
public static final String TIER_OBTAIN_CHANCE_ENCHANTING = "%tier_obtain_chance_enchanting%";
|
||||
public static final String TIER_OBTAIN_CHANCE_VILLAGER = "%tier_obtain_chance_villager%";
|
||||
public static final String TIER_OBTAIN_CHANCE_LOOT_GENERATION = "%tier_obtain_chance_loot_generation%";
|
||||
public static final String TIER_OBTAIN_CHANCE_FISHING = "%tier_obtain_chance_fishing%";
|
||||
public static final String TIER_OBTAIN_CHANCE_MOB_SPAWNING = "%tier_obtain_chance_mob_spawning%";
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment;
|
||||
|
||||
public interface Cleanable {
|
||||
|
||||
void clear();
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.meta;
|
||||
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface Arrowed {
|
||||
|
||||
@NotNull Arrowed getArrowImplementation();
|
||||
|
||||
@NotNull
|
||||
default Optional<UniParticle> getTrailParticle() {
|
||||
return this.getArrowImplementation().getTrailParticle();
|
||||
}
|
||||
|
||||
default void addTrail(@NotNull Projectile projectile) {
|
||||
this.getArrowImplementation().addTrail(projectile);
|
||||
}
|
||||
|
||||
default void addData(@NotNull Projectile projectile) {
|
||||
this.getArrowImplementation().addData(projectile);
|
||||
}
|
||||
|
||||
default boolean isOurProjectile(@NotNull Projectile projectile) {
|
||||
return this.getArrowImplementation().isOurProjectile(projectile);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.meta;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface Chanced {
|
||||
|
||||
@NotNull Chanced getChanceImplementation();
|
||||
|
||||
/*@NotNull
|
||||
default UnaryOperator<String> replacePlaceholders(int level) {
|
||||
return this.getChanceImplementation().replacePlaceholders(level);
|
||||
}*/
|
||||
|
||||
default double getTriggerChance(int level) {
|
||||
return this.getChanceImplementation().getTriggerChance(level);
|
||||
}
|
||||
|
||||
default boolean checkTriggerChance(int level) {
|
||||
return getChanceImplementation().checkTriggerChance(level);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.meta;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface Periodic {
|
||||
|
||||
@NotNull Periodic getPeriodImplementation();
|
||||
|
||||
default long getInterval() {
|
||||
return this.getPeriodImplementation().getInterval();
|
||||
}
|
||||
|
||||
default long getNextTriggerTime() {
|
||||
return this.getPeriodImplementation().getNextTriggerTime();
|
||||
}
|
||||
|
||||
default boolean isTriggerTime() {
|
||||
return this.getPeriodImplementation().isTriggerTime();
|
||||
}
|
||||
|
||||
default void updateTriggerTime() {
|
||||
this.getPeriodImplementation().updateTriggerTime();
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.meta;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface Potioned {
|
||||
|
||||
@NotNull Potioned getPotionImplementation();
|
||||
|
||||
default boolean isPermanent() {
|
||||
return this.getPotionImplementation().isPermanent();
|
||||
}
|
||||
|
||||
default PotionEffectType getEffectType() {
|
||||
return this.getPotionImplementation().getEffectType();
|
||||
}
|
||||
|
||||
default int getEffectAmplifier(int level) {
|
||||
return this.getPotionImplementation().getEffectAmplifier(level);
|
||||
}
|
||||
|
||||
default int getEffectDuration(int level) {
|
||||
return this.getPotionImplementation().getEffectDuration(level);
|
||||
}
|
||||
|
||||
default PotionEffect createEffect(int level) {
|
||||
return this.getPotionImplementation().createEffect(level);
|
||||
}
|
||||
|
||||
default boolean addEffect(@NotNull LivingEntity target, int level) {
|
||||
return this.getPotionImplementation().addEffect(target, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface BlockBreakEnchant extends IEnchantment {
|
||||
|
||||
boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level);
|
||||
|
||||
@NotNull
|
||||
default EventPriority getBreakPriority() {
|
||||
return EventPriority.HIGH;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockDropItemEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface BlockDropEnchant extends IEnchantment {
|
||||
|
||||
boolean onDrop(@NotNull BlockDropItemEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level);
|
||||
|
||||
@NotNull
|
||||
default EventPriority getDropPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface BowEnchant extends IEnchantment {
|
||||
|
||||
boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level);
|
||||
|
||||
boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level);
|
||||
|
||||
boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile,
|
||||
@NotNull LivingEntity shooter, @NotNull LivingEntity victim,
|
||||
@NotNull ItemStack weapon, int level);
|
||||
|
||||
@NotNull
|
||||
default EventPriority getShootPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default EventPriority getHitPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default EventPriority getDamagePriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface CombatEnchant extends IEnchantment {
|
||||
|
||||
boolean onAttack(@NotNull EntityDamageByEntityEvent event,
|
||||
@NotNull LivingEntity damager, @NotNull LivingEntity victim,
|
||||
@NotNull ItemStack weapon, int level);
|
||||
|
||||
boolean onProtect(@NotNull EntityDamageByEntityEvent event,
|
||||
@NotNull LivingEntity damager, @NotNull LivingEntity victim,
|
||||
@NotNull ItemStack weapon, int level);
|
||||
|
||||
@NotNull
|
||||
default EventPriority getAttackPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default EventPriority getProtectPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface DamageEnchant extends IEnchantment {
|
||||
|
||||
boolean onDamage(@NotNull EntityDamageEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level);
|
||||
|
||||
@NotNull
|
||||
default EventPriority getDamagePriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityResurrectEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface DeathEnchant extends IEnchantment {
|
||||
|
||||
boolean onDeath(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, ItemStack item, int level);
|
||||
|
||||
boolean onKill(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, @NotNull Player killer, ItemStack weapon, int level);
|
||||
|
||||
boolean onResurrect(@NotNull EntityResurrectEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level);
|
||||
|
||||
@NotNull
|
||||
default EventPriority getDeathPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default EventPriority getKillPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface FishingEnchant extends IEnchantment {
|
||||
|
||||
boolean onFishing(@NotNull PlayerFishEvent event, @NotNull ItemStack item, int level);
|
||||
|
||||
@NotNull
|
||||
default EventPriority getFishingPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface GenericEnchant extends IEnchantment {
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
|
||||
public interface InteractEnchant extends IEnchantment {
|
||||
|
||||
boolean onInteract(@NotNull PlayerInteractEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level);
|
||||
|
||||
@NotNull
|
||||
default EventPriority getInteractPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package su.nightexpress.excellentenchants.api.enchantment.type;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Periodic;
|
||||
|
||||
public interface PassiveEnchant extends IEnchantment, Periodic {
|
||||
|
||||
boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level);
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package su.nightexpress.excellentenchants.command;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.command.AbstractCommand;
|
||||
import su.nexmedia.engine.api.command.CommandResult;
|
||||
import su.nexmedia.engine.utils.CollectionsUtil;
|
||||
import su.nexmedia.engine.utils.PlayerUtil;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Perms;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.config.Lang;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
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);
|
||||
this.setDescription(plugin.getMessage(Lang.COMMAND_BOOK_DESC));
|
||||
this.setUsage(plugin.getMessage(Lang.COMMAND_BOOK_USAGE));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<String> getTab(@NotNull Player player, int arg, @NotNull String[] args) {
|
||||
if (arg == 1) {
|
||||
return CollectionsUtil.playerNames(player);
|
||||
}
|
||||
if (arg == 2) {
|
||||
return Arrays.stream(Enchantment.values()).map(e -> e.getKey().getKey()).toList();
|
||||
}
|
||||
if (arg == 3) {
|
||||
return Arrays.asList("-1", "1", "5", "10");
|
||||
}
|
||||
return super.getTab(player, arg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
|
||||
if (result.length() < 4) {
|
||||
this.printUsage(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = PlayerUtil.getPlayer(result.getArg(1));
|
||||
if (player == null) {
|
||||
this.errorPlayer(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(result.getArg(2).toLowerCase()));
|
||||
if (enchantment == null) {
|
||||
plugin.getMessage(Lang.ERROR_NO_ENCHANT).send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
int level = result.getInt(3, -1);
|
||||
if (level < 1) {
|
||||
level = Rnd.get(enchantment.getStartLevel(), enchantment.getMaxLevel());
|
||||
}
|
||||
|
||||
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
|
||||
EnchantUtils.add(item, enchantment, level, true);
|
||||
EnchantUtils.updateDisplay(item);
|
||||
PlayerUtil.addItem(player, item);
|
||||
|
||||
plugin.getMessage(Lang.COMMAND_BOOK_DONE)
|
||||
.replace(Placeholders.GENERIC_ENCHANT, EnchantUtils.getLocalized(enchantment))
|
||||
.replace(Placeholders.forPlayer(player))
|
||||
.send(sender);
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package su.nightexpress.excellentenchants.command;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.command.AbstractCommand;
|
||||
import su.nexmedia.engine.api.command.CommandResult;
|
||||
import su.nexmedia.engine.utils.*;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Perms;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.config.Lang;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
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);
|
||||
this.setDescription(plugin.getMessage(Lang.COMMAND_ENCHANT_DESC));
|
||||
this.setUsage(plugin.getMessage(Lang.COMMAND_ENCHANT_USAGE));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<String> getTab(@NotNull Player player, int arg, @NotNull String[] args) {
|
||||
if (arg == 1) {
|
||||
return Arrays.stream(Enchantment.values()).map(e -> e.getKey().getKey()).toList();
|
||||
}
|
||||
if (arg == 2) {
|
||||
return Arrays.asList("-1", "1", "5", "10");
|
||||
}
|
||||
if (arg == 3) {
|
||||
return CollectionsUtil.playerNames(player);
|
||||
}
|
||||
if (arg == 4) {
|
||||
return CollectionsUtil.getEnumsList(EquipmentSlot.class);
|
||||
}
|
||||
return super.getTab(player, arg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
|
||||
if (result.length() < 3) {
|
||||
this.printUsage(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(result.getArg(1).toLowerCase()));
|
||||
if (enchantment == null) {
|
||||
plugin.getMessage(Lang.ERROR_NO_ENCHANT).send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = PlayerUtil.getPlayer(result.getArg(3, sender.getName()));
|
||||
if (player == null) {
|
||||
this.errorPlayer(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
EquipmentSlot slot = StringUtil.getEnum(result.getArg(4, ""), EquipmentSlot.class).orElse(EquipmentSlot.HAND);
|
||||
|
||||
ItemStack item = player.getInventory().getItem(slot);
|
||||
if (item == null || item.getType().isAir()) {
|
||||
this.plugin.getMessage(Lang.COMMAND_ENCHANT_ERROR_NO_ITEM).send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
int level = result.getInt(2, -1);
|
||||
if (level < 0) {
|
||||
level = Rnd.get(enchantment.getStartLevel(), enchantment.getMaxLevel());
|
||||
}
|
||||
|
||||
if (level > 0) {
|
||||
EnchantUtils.add(item, enchantment, level, true);
|
||||
}
|
||||
else EnchantUtils.remove(item, enchantment);
|
||||
|
||||
EnchantUtils.updateDisplay(item);
|
||||
player.getInventory().setItem(slot, item);
|
||||
|
||||
plugin.getMessage(sender == player ? Lang.COMMAND_ENCHANT_DONE_SELF : Lang.COMMAND_ENCHANT_DONE_OTHERS)
|
||||
.replace(Placeholders.forPlayer(player))
|
||||
.replace(Placeholders.GENERIC_ITEM, ItemUtil.getItemName(item))
|
||||
.replace(Placeholders.GENERIC_ENCHANT, EnchantUtils.getLocalized(enchantment))
|
||||
.replace(Placeholders.GENERIC_LEVEL, NumberUtil.toRoman(level))
|
||||
.send(sender);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package su.nightexpress.excellentenchants.command;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.command.AbstractCommand;
|
||||
import su.nexmedia.engine.api.command.CommandResult;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Perms;
|
||||
import su.nightexpress.excellentenchants.config.Lang;
|
||||
|
||||
public class ListCommand extends AbstractCommand<ExcellentEnchants> {
|
||||
|
||||
public ListCommand(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, new String[]{"list"}, Perms.COMMAND_LIST);
|
||||
this.setDescription(plugin.getMessage(Lang.COMMAND_LIST_DESC));
|
||||
this.setPlayerOnly(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
|
||||
plugin.getEnchantManager().getEnchantsListGUI().open((Player) sender, 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package su.nightexpress.excellentenchants.command;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.command.AbstractCommand;
|
||||
import su.nexmedia.engine.api.command.CommandResult;
|
||||
import su.nexmedia.engine.utils.CollectionsUtil;
|
||||
import su.nexmedia.engine.utils.Placeholders;
|
||||
import su.nexmedia.engine.utils.PlayerUtil;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Perms;
|
||||
import su.nightexpress.excellentenchants.config.Lang;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
import su.nightexpress.excellentenchants.tier.Tier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class TierbookCommand extends AbstractCommand<ExcellentEnchants> {
|
||||
|
||||
public TierbookCommand(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, new String[]{"tierbook"}, Perms.COMMAND_TIERBOOK);
|
||||
this.setDescription(plugin.getMessage(Lang.COMMAND_TIER_BOOK_DESC));
|
||||
this.setUsage(plugin.getMessage(Lang.COMMAND_TIER_BOOK_USAGE));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<String> getTab(@NotNull Player player, int arg, @NotNull String[] args) {
|
||||
if (arg == 1) {
|
||||
return CollectionsUtil.playerNames(player);
|
||||
}
|
||||
if (arg == 2) {
|
||||
return plugin.getTierManager().getTierIds();
|
||||
}
|
||||
if (arg == 3) {
|
||||
return Arrays.asList("-1", "1", "5", "10");
|
||||
}
|
||||
return super.getTab(player, arg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) {
|
||||
if (result.length() < 4) {
|
||||
this.printUsage(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = PlayerUtil.getPlayer(result.getArg(1));
|
||||
if (player == null) {
|
||||
this.errorPlayer(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Tier tier = plugin.getTierManager().getTierById(result.getArg(2).toLowerCase());
|
||||
if (tier == null) {
|
||||
plugin.getMessage(Lang.COMMAND_TIER_BOOK_ERROR).send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
Set<ExcellentEnchant> enchants = EnchantRegistry.getOfTier(tier);
|
||||
ExcellentEnchant enchant = enchants.isEmpty() ? null : Rnd.get(enchants);
|
||||
if (enchant == null) {
|
||||
plugin.getMessage(Lang.ERROR_NO_ENCHANT).send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
int level = result.getInt(3, -1);
|
||||
if (level < 1) {
|
||||
level = Rnd.get(enchant.getStartLevel(), enchant.getMaxLevel());
|
||||
}
|
||||
|
||||
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
|
||||
EnchantUtils.add(item, enchant.getBackend(), level, true);
|
||||
EnchantUtils.updateDisplay(item);
|
||||
PlayerUtil.addItem(player, item);
|
||||
|
||||
plugin.getMessage(Lang.COMMAND_TIER_BOOK_DONE)
|
||||
.replace(tier.replacePlaceholders())
|
||||
.replace(Placeholders.forPlayer(player))
|
||||
.send(sender);
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
package su.nightexpress.excellentenchants.config;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.utils.Colorizer;
|
||||
import su.nexmedia.engine.utils.Colors2;
|
||||
import su.nexmedia.engine.utils.StringUtil;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
|
||||
import su.nightexpress.excellentenchants.tier.Tier;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Config {
|
||||
|
||||
public static final String DIR_MENU = "/menu/";
|
||||
|
||||
public static final JOption<Long> TASKS_ARROW_TRAIL_TICKS_INTERVAL = JOption.create("Tasks.Arrow_Trail.Tick_Interval",
|
||||
1L,
|
||||
"Sets how often (in ticks) arrow trail particle effects will be spawned behind the arrow."
|
||||
);
|
||||
|
||||
public static final JOption<Long> TASKS_PASSIVE_ENCHANTS_TRIGGER_INTERVAL = JOption.create("Tasks.Passive_Enchants.Trigger_Interval",
|
||||
100L,
|
||||
"Sets how often (in ticks) the plugin will attempt to trigger passive enchantment effects on all alive entities.",
|
||||
"For best results it's recommened to keep this value smaller, but at the same rate as enchantment 'Trigger_Interval' settings.",
|
||||
"Examples:",
|
||||
"--- Global: 100 ticks; Regrowth: 100 ticks; Saturation: 100 ticks;",
|
||||
"--- Global: 50 ticks, Regrowth: 100 ticks; Saturation: 150 ticks;"
|
||||
);
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_INTERNAL_HANDLER = JOption.create("Enchantments.Internal_Distributor", false,
|
||||
"[EXPERIMENTAL - DO NOT TOUCH]",
|
||||
"Sets whether or not enchantment distribution will be handled by vanilla server mechanics.");
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_CHARGES_ENABLED = JOption.create("Enchantments.Charges.Enabled",
|
||||
false,
|
||||
"Enables the enchantment Charges feature.",
|
||||
Placeholders.URL_WIKI + "Charges-System");
|
||||
|
||||
public static final JOption<TreeMap<Integer, String>> ENCHANTMENTS_CHARGES_FORMAT = new JOption<TreeMap<Integer, String>>("Enchantments.Charges.Format",
|
||||
(cfg, path, def) -> {
|
||||
TreeMap<Integer, String> map = new TreeMap<>();
|
||||
for (String raw : cfg.getSection(path)) {
|
||||
int percent = StringUtil.getInteger(raw, -1);
|
||||
if (percent < 0) continue;
|
||||
|
||||
String format = Colorizer.apply(cfg.getString(path + "." + raw, ""));
|
||||
if (format.isEmpty()) continue;
|
||||
|
||||
map.put(percent, format);
|
||||
}
|
||||
return map;
|
||||
},
|
||||
() -> {
|
||||
TreeMap<Integer, String> map = new TreeMap<>();
|
||||
map.put(0, "#ff9a9a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
|
||||
map.put(25, "#ffc39a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
|
||||
map.put(50, "#f6ff9a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
|
||||
map.put(75, "#bcff9a(" + Placeholders.GENERIC_AMOUNT + "⚡)");
|
||||
return map;
|
||||
},
|
||||
"Enchantment charges format depends on amount of charges left (in percent).",
|
||||
"If you don't want to display charges, leave only keys with negative values.",
|
||||
"Use '" + Placeholders.GENERIC_AMOUNT + "' placeholder for amount of charges.")
|
||||
.setWriter((cfg, path, map) -> map.forEach((perc, str) -> cfg.set(path + "." + perc, str)));
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_CHARGES_COMPARE_TYPE_ONLY = JOption.create("Enchantments.Charges.Compare_Material_Only", false,
|
||||
"When enabled, only item material will be checked to determine if item can be used as an enchantment fuel.",
|
||||
"When disabled (default), it will compare the whole item meta including name, lore, model data etc.");
|
||||
|
||||
public static final JOption<ItemStack> ENCHANTMENTS_CHARGES_FUEL_ITEM = JOption.create("Enchantments.Charges.Fuel_Item",
|
||||
new ItemStack(Material.LAPIS_LAZULI),
|
||||
"Default item used to recharge item's enchantments on anvils.",
|
||||
"If you want different item for certain enchantments, you can do it in that enchantment configs.",
|
||||
"Item Options: " + Placeholders.URL_ENGINE_SCALER)
|
||||
.setWriter(JYML::setItem);
|
||||
|
||||
public static final JOption<Set<String>> ENCHANTMENTS_DISABLED = JOption.create("Enchantments.Disabled",
|
||||
Set.of("enchant_name", "other_enchant"),
|
||||
"A list of enchantments, that will be disabled and removed from the game (server).",
|
||||
"Enchantment names are the same as enchantment file name in /enchants/ folder. ! Must be in lower_case !",
|
||||
"Example: To disable 'Explosive Arrows' you need to add 'explosive_arrows' here.")
|
||||
.mapReader(set -> set.stream().map(String::toLowerCase).collect(Collectors.toSet()));
|
||||
|
||||
public static final JOption<Map<String, Set<String>>> ENCHANTMENTS_DISABLED_IN_WORLDS = new JOption<Map<String, Set<String>>>("Enchantments.Disabled_In_Worlds",
|
||||
(cfg, path, def) -> cfg.getSection(path).stream().collect(Collectors.toMap(k -> k, worldName -> cfg.getStringSet(path + "." + worldName))),
|
||||
() -> Map.of("your_world_name", Set.of("enchantment_name", "ice_aspect")),
|
||||
"Here you can disable certain enchantments in certain worlds.",
|
||||
"Enchantment names are the same as enchantment file name in /enchants/ folder. ! Must be in lower_case !",
|
||||
"To disable all enchantments for a world, use '" + Placeholders.WILDCARD + "' instead of enchantment names.")
|
||||
.setWriter((cfg, path, map) -> map.forEach((world, enchants) -> cfg.set(path + "." + world, enchants)));
|
||||
|
||||
public static final JOption<Integer> ENCHANTMENTS_DISPLAY_MODE = JOption.create("Enchantments.Display.Mode",
|
||||
1,
|
||||
"Sets how enchantment names and descriptions will be handled on items.",
|
||||
"1 = Plain modification of item's lore (lore changes are real and persistent).",
|
||||
"2 = Packet modification of item's lore (no real changes are made to the items). Requires ProtocolLib.",
|
||||
"Plain mode is faster, but may not reflect all changes immediately.",
|
||||
"Packet mode is slower, but instantly reflect all changes. In creative mode, there is a chance for lore duplication.");
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_DESCRIPTION_ENABLED = JOption.create("Enchantments.Description.Enabled", true,
|
||||
"When 'true', adds the enchantment description to item lore under enchantment names.",
|
||||
"For Display-Mode = 2 description is not shown while you're in Creative gamemode.");
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_DESCRIPTION_BOOKS_ONLY = JOption.create("Enchantments.Description.Books_Only",
|
||||
false,
|
||||
"Sets whether or not only enchanted books will have enchantment descriptions.");
|
||||
|
||||
public static final JOption<String> ENCHANTMENTS_DESCRIPTION_FORMAT = JOption.create("Enchantments.Description.Format",
|
||||
"&8▸ " + Placeholders.GENERIC_DESCRIPTION,
|
||||
"Sets the global enchantment description format.").mapReader(Colorizer::apply);
|
||||
|
||||
public static final JOption<Integer> ENCHANTMENTS_ITEM_CUSTOM_MAX = JOption.create("Enchantments.Item.Max_Custom_Enchants", 3,
|
||||
"How many of custom enchantments the item can contain at the same time?");
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_ITEM_SWORD_ENCHANTS_TO_AXES = JOption.create("Enchantments.Item.Sword_Enchants_To_Axes", true,
|
||||
"Set this to 'true' to allow Sword enchantments for Axes.");
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_ITEM_BOW_ENCHANTS_TO_CROSSBOW = JOption.create("Enchantments.Item.Bow_Enchants_To_Crossbows", true,
|
||||
"Set this to 'true' to allow Bow enchantments for Crossbows.");
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_ITEM_CHESTPLATE_ENCHANTS_TO_ELYTRA = JOption.create("Enchantments.Item.Chestplate_Enchants_To_Elytra", false,
|
||||
"Set this to 'true' to allow Chestplate enchantments for Elytras.");
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_ENTITY_PASSIVE_FOR_MOBS = JOption.create("Enchantments.Entity.Apply_Passive_Enchants_To_Mobs", true,
|
||||
"When enabled, passive enchantments (permanent potion effects, regeneration, etc.) will be applied to mobs as well.",
|
||||
"Disable this if you're experiencing performance issues.");
|
||||
|
||||
public static final JOption<Boolean> ENCHANTMENTS_SINGLE_ENCHANT_IN_VILLAGER_BOOKS = JOption.create("Enchantments.Single_Enchant_In_Villager_Books", true,
|
||||
"Sets whether or not enchanted books in villager trades will have only 1 enchant, vanilla or custom one.");
|
||||
|
||||
private static final JOption<Map<ObtainType, ObtainSettings>> OBTAIN_SETTINGS = new JOption<Map<ObtainType, ObtainSettings>>("Enchantments.Obtaining",
|
||||
(cfg, path, def) -> Stream.of(ObtainType.values()).collect(Collectors.toMap(k -> k, v -> ObtainSettings.read(cfg, path + "." + v.getPathName()))),
|
||||
() -> Stream.of(ObtainType.values()).collect(Collectors.toMap(k -> k, v -> new ObtainSettings(true, 4, 80D, 0, 2))),
|
||||
"Settings for the different ways of obtaining enchantments.")
|
||||
.setWriter((cfg, path, map) -> map.forEach((type, settings) -> ObtainSettings.write(cfg, path + "." + type.getPathName(), settings)));
|
||||
|
||||
@NotNull
|
||||
public static Optional<ObtainSettings> getObtainSettings(@NotNull ObtainType obtainType) {
|
||||
ObtainSettings settings = OBTAIN_SETTINGS.get().get(obtainType);
|
||||
return settings == null || !settings.isEnabled() ? Optional.empty() : Optional.of(settings);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<Tier> getDefaultTiers() {
|
||||
List<Tier> list = new ArrayList<>();
|
||||
list.add(new Tier("common", 1, "Common", Colors2.WHITE, getObtainWeight(50D)));
|
||||
list.add(new Tier("rare", 2, "Rare", Colors2.GREEN, getObtainWeight(25D)));
|
||||
list.add(new Tier("unique", 3, "Unique", Colors2.YELLOW, getObtainWeight(15D)));
|
||||
list.add(new Tier("legendary", 4, "Legendary", Colors2.ORANGE, getObtainWeight(5D)));
|
||||
return list;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<ObtainType, Double> getObtainWeight(double weight) {
|
||||
Map<ObtainType, Double> map = new HashMap<>();
|
||||
for (ObtainType obtainType : ObtainType.values()) {
|
||||
map.put(obtainType, weight);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package su.nightexpress.excellentenchants.config;
|
||||
|
||||
import su.nexmedia.engine.api.lang.LangKey;
|
||||
import su.nexmedia.engine.lang.EngineLang;
|
||||
|
||||
import static su.nexmedia.engine.utils.Colors2.*;
|
||||
import static su.nightexpress.excellentenchants.Placeholders.*;
|
||||
|
||||
public class Lang extends EngineLang {
|
||||
|
||||
public static final LangKey COMMAND_LIST_DESC = LangKey.of("Command.List.Desc", "List of all custom enchantments.");
|
||||
|
||||
public static final LangKey COMMAND_ENCHANT_USAGE = LangKey.of("Command.Enchant.Usage", "<enchant> <level> [player] [slot]");
|
||||
public static final LangKey COMMAND_ENCHANT_DESC = LangKey.of("Command.Enchant.Desc", "Enchants the item in your hand.");
|
||||
public static final LangKey COMMAND_ENCHANT_DONE_SELF = LangKey.of("Command.Enchant.Done.Self", LIGHT_ORANGE + GENERIC_ITEM + LIGHT_YELLOW + " enchanted with " + GENERIC_ENCHANT + " " + GENERIC_LEVEL + LIGHT_YELLOW + "!");
|
||||
public static final LangKey COMMAND_ENCHANT_DONE_OTHERS = LangKey.of("Command.Enchant.Done.Others", LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + "'s " + LIGHT_ORANGE + GENERIC_ITEM + LIGHT_YELLOW + " enchanted with " + GENERIC_ENCHANT + " " + GENERIC_LEVEL + LIGHT_YELLOW + "!");
|
||||
public static final LangKey COMMAND_ENCHANT_ERROR_NO_ITEM = LangKey.of("Command.Enchant.Error.NoItem", RED + "There is no item to enchant!");
|
||||
|
||||
public static final LangKey COMMAND_BOOK_USAGE = LangKey.of("Command.Book.Usage", "<player> <enchant> <level>");
|
||||
public static final LangKey COMMAND_BOOK_DESC = LangKey.of("Command.Book.Desc", "Gives custom enchanted book.");
|
||||
public static final LangKey COMMAND_BOOK_DONE = LangKey.of("Command.Book.Done", LIGHT_YELLOW + "Given " + LIGHT_ORANGE + GENERIC_ENCHANT + LIGHT_YELLOW + " enchanted book to " + LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + ".");
|
||||
|
||||
public static final LangKey COMMAND_TIER_BOOK_USAGE = LangKey.of("Command.TierBook.Usage", "<player> <tier> <level>");
|
||||
public static final LangKey COMMAND_TIER_BOOK_DESC = LangKey.of("Command.TierBook.Desc", "Gives an enchanted book.");
|
||||
public static final LangKey COMMAND_TIER_BOOK_ERROR = LangKey.of("Command.TierBook.Error", RED + "Invalid tier!");
|
||||
public static final LangKey COMMAND_TIER_BOOK_DONE = LangKey.of("Command.TierBook.Done", LIGHT_YELLOW + "Given " + LIGHT_ORANGE + TIER_NAME + LIGHT_YELLOW + " enchanted book to " + LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + ".");
|
||||
|
||||
public static final LangKey ERROR_NO_ENCHANT = LangKey.of("Error.NoEnchant", RED + "Invalid enchantment.");
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package su.nightexpress.excellentenchants.config;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
|
||||
public class ObtainSettings {
|
||||
|
||||
private final boolean isEnabled;
|
||||
private final int enchantsTotalMax;
|
||||
private final double enchantsCustomGenerationChance;
|
||||
private final int enchantsCustomMin;
|
||||
private final int enchantsCustomMax;
|
||||
|
||||
public ObtainSettings(boolean isEnabled,
|
||||
int enchantsTotalMax, double enchantsCustomGenerationChance,
|
||||
int enchantsCustomMin, int enchantsCustomMax) {
|
||||
this.isEnabled = isEnabled;
|
||||
this.enchantsTotalMax = enchantsTotalMax;
|
||||
this.enchantsCustomGenerationChance = enchantsCustomGenerationChance;
|
||||
this.enchantsCustomMin = enchantsCustomMin;
|
||||
this.enchantsCustomMax = enchantsCustomMax;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ObtainSettings read(@NotNull JYML cfg, @NotNull String path) {
|
||||
boolean isEnabled = cfg.getBoolean(path + ".Enabled");
|
||||
int enchantsTotalMax = cfg.getInt(path + ".Enchantments.Total_Maximum", 4);
|
||||
double enchantsCustomGenerationChance = cfg.getDouble(path + ".Enchantments.Custom_Generation_Chance", 50D);
|
||||
int enchantsCustomMin = cfg.getInt(path + ".Enchantments.Custom_Minimum", 0);
|
||||
int enchantsCustomMax = cfg.getInt(path + ".Enchantments.Custom_Maximum", 2);
|
||||
|
||||
return new ObtainSettings(isEnabled, enchantsTotalMax, enchantsCustomGenerationChance, enchantsCustomMin, enchantsCustomMax);
|
||||
}
|
||||
|
||||
public static void write(@NotNull JYML cfg, @NotNull String path, @NotNull ObtainSettings settings) {
|
||||
cfg.set(path + ".Enabled", settings.isEnabled());
|
||||
cfg.set(path + ".Enchantments.Total_Maximum", settings.getEnchantsTotalMax());
|
||||
cfg.set(path + ".Enchantments.Custom_Generation_Chance", settings.getEnchantsCustomGenerationChance());
|
||||
cfg.set(path + ".Enchantments.Custom_Minimum", settings.getEnchantsCustomMin());
|
||||
cfg.set(path + ".Enchantments.Custom_Maximum", settings.getEnchantsCustomMax());
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public int getEnchantsTotalMax() {
|
||||
return enchantsTotalMax;
|
||||
}
|
||||
|
||||
public double getEnchantsCustomGenerationChance() {
|
||||
return enchantsCustomGenerationChance;
|
||||
}
|
||||
|
||||
public int getEnchantsCustomMin() {
|
||||
return enchantsCustomMin;
|
||||
}
|
||||
|
||||
public int getEnchantsCustomMax() {
|
||||
return enchantsCustomMax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ObtainSettings{" + "enchantsTotalMax=" + enchantsTotalMax + ", enchantsCustomGenerationChance=" + enchantsCustomGenerationChance + ", enchantsCustomMin=" + enchantsCustomMin + ", enchantsCustomMax=" + enchantsCustomMax + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.151.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* org.jetbrains.annotations.NotNull
|
||||
* su.nexmedia.engine.NexPlugin
|
||||
* su.nexmedia.engine.api.manager.AbstractManager
|
||||
* su.nexmedia.engine.api.manager.EventListener
|
||||
*/
|
||||
package su.nightexpress.excellentenchants.enchantment;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.manager.AbstractManager;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.enchantment.listener.EnchantAnvilListener;
|
||||
import su.nightexpress.excellentenchants.enchantment.listener.EnchantGenericListener;
|
||||
import su.nightexpress.excellentenchants.enchantment.menu.EnchantmentsListMenu;
|
||||
import su.nightexpress.excellentenchants.enchantment.task.ArrowTrailsTask;
|
||||
import su.nightexpress.excellentenchants.enchantment.task.PassiveEnchantsTask;
|
||||
|
||||
public class EnchantManager
|
||||
extends AbstractManager<ExcellentEnchants> {
|
||||
|
||||
public static final String DIR_ENCHANTS = "/enchants/";
|
||||
private EnchantmentsListMenu enchantmentsListMenu;
|
||||
private ArrowTrailsTask arrowTrailsTask;
|
||||
private PassiveEnchantsTask passiveEnchantsTask;
|
||||
|
||||
public EnchantManager(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
protected void onLoad() {
|
||||
this.enchantmentsListMenu = new EnchantmentsListMenu(this.plugin);
|
||||
this.addListener(new EnchantGenericListener(this));
|
||||
this.addListener(new EnchantAnvilListener(this.plugin));
|
||||
this.arrowTrailsTask = new ArrowTrailsTask(this.plugin);
|
||||
this.arrowTrailsTask.start();
|
||||
this.passiveEnchantsTask = new PassiveEnchantsTask(this.plugin);
|
||||
this.passiveEnchantsTask.start();
|
||||
}
|
||||
|
||||
protected void onShutdown() {
|
||||
if (this.enchantmentsListMenu != null) {
|
||||
this.enchantmentsListMenu.clear();
|
||||
this.enchantmentsListMenu = null;
|
||||
}
|
||||
if (this.arrowTrailsTask != null) {
|
||||
this.arrowTrailsTask.stop();
|
||||
this.arrowTrailsTask = null;
|
||||
}
|
||||
if (this.passiveEnchantsTask != null) {
|
||||
this.passiveEnchantsTask.stop();
|
||||
this.passiveEnchantsTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantmentsListMenu getEnchantsListGUI() {
|
||||
return this.enchantmentsListMenu;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,232 @@
|
||||
package su.nightexpress.excellentenchants.enchantment;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
import su.nightexpress.excellentenchants.config.ObtainSettings;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
import su.nightexpress.excellentenchants.tier.Tier;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class EnchantPopulator {
|
||||
|
||||
private final ExcellentEnchants plugin;
|
||||
private final ObtainType obtainType;
|
||||
private final ItemStack item;
|
||||
private final Map<Tier, Set<ExcellentEnchant>> candidates;
|
||||
private final Map<Enchantment, Integer> population;
|
||||
|
||||
private World world;
|
||||
private Function<ExcellentEnchant, Integer> levelGenerator;
|
||||
|
||||
public EnchantPopulator(@NotNull ExcellentEnchants plugin, @NotNull ItemStack item, @NotNull ObtainType obtainType) {
|
||||
this.plugin = plugin;
|
||||
this.item = item;
|
||||
this.obtainType = obtainType;
|
||||
this.candidates = new HashMap<>();
|
||||
this.population = new HashMap<>();
|
||||
this.withLevelGenerator(enchant -> enchant.generateLevel(this.getObtainType()));
|
||||
|
||||
this.fillDefaultCandidates();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantPopulator withWorld(@NotNull World world) {
|
||||
this.world = world;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantPopulator withLevelGenerator(@NotNull Function<ExcellentEnchant, Integer> levelGenerator) {
|
||||
this.levelGenerator = levelGenerator;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantPopulator withDefaultPopulation(@NotNull Map<Enchantment, Integer> population) {
|
||||
this.getPopulation().putAll(population);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void fillDefaultCandidates() {
|
||||
this.plugin.getTierManager().getTiers().forEach(tier -> {
|
||||
Set<ExcellentEnchant> enchants = EnchantRegistry.getOfTier(tier);
|
||||
|
||||
enchants.removeIf(enchant -> {
|
||||
return !enchant.isObtainable(this.getObtainType()) || (!enchant.getBackend().canEnchantItem(this.getItem()) && !EnchantUtils.isBook(this.getItem()));
|
||||
});
|
||||
|
||||
this.candidates.put(tier, enchants);
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.getCandidates().isEmpty() || this.getCandidates().values().stream().allMatch(Set::isEmpty);
|
||||
}
|
||||
|
||||
public boolean isEmpty(@NotNull Tier tier) {
|
||||
return this.getCandidates(tier).isEmpty();
|
||||
}
|
||||
|
||||
public void purge(@NotNull Tier tier) {
|
||||
this.getCandidates().remove(tier);
|
||||
}
|
||||
|
||||
public void purge(@NotNull Tier tier, @NotNull ExcellentEnchant enchant) {
|
||||
this.getCandidates(tier).remove(enchant);
|
||||
this.getCandidates().keySet().removeIf(this::isEmpty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ObtainType getObtainType() {
|
||||
return obtainType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Function<ExcellentEnchant, Integer> getLevelGenerator() {
|
||||
return levelGenerator;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<Tier, Set<ExcellentEnchant>> getCandidates() {
|
||||
return this.candidates;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<ExcellentEnchant> getCandidates(@NotNull Tier tier) {
|
||||
return this.getCandidates().getOrDefault(tier, new HashSet<>());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<Enchantment, Integer> getPopulation() {
|
||||
return this.population;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Tier getTierByChance() {
|
||||
Map<Tier, Double> map = this.getCandidates().keySet().stream()
|
||||
.filter(tier -> tier.getChance(this.getObtainType()) > 0D)
|
||||
.collect(Collectors.toMap(k -> k, v -> v.getChance(this.getObtainType()), (o, n) -> n, HashMap::new));
|
||||
if (map.isEmpty()) return null;
|
||||
|
||||
return Rnd.getByWeight(map);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ExcellentEnchant getEnchantByChance(@NotNull Tier tier) {
|
||||
Map<ExcellentEnchant, Double> map = this.getCandidates(tier).stream()
|
||||
.collect(Collectors.toMap(k -> k, v -> v.getObtainChance(this.getObtainType())));
|
||||
return map.isEmpty() ? null : Rnd.getByWeight(map);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<Enchantment, Integer> createPopulation() {
|
||||
Map<Enchantment, Integer> population = this.getPopulation();
|
||||
|
||||
ObtainSettings settings = Config.getObtainSettings(this.getObtainType()).orElse(null);
|
||||
if (settings == null || !Rnd.chance(settings.getEnchantsCustomGenerationChance())) return population;
|
||||
|
||||
int enchantsLimit = settings.getEnchantsTotalMax();
|
||||
int enchantsRolled = Rnd.get(settings.getEnchantsCustomMin(), settings.getEnchantsCustomMax());
|
||||
|
||||
// Try to populate as many as possible.
|
||||
while (!this.isEmpty() && enchantsRolled > 0) {
|
||||
// Limit reached.
|
||||
if (population.size() >= enchantsLimit) break;
|
||||
|
||||
Tier tier = this.getTierByChance();
|
||||
if (tier == null) break; // no tiers left.
|
||||
|
||||
ExcellentEnchant enchant = this.getEnchantByChance(tier);
|
||||
// Remove entire tier if no enchants can be selected.
|
||||
if (enchant == null) {
|
||||
this.purge(tier);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove disabled world enchants.
|
||||
if (world != null && enchant.isDisabledInWorld(world)) {
|
||||
this.purge(tier, enchant);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove conflicting enchants.
|
||||
if (population.keySet().stream().anyMatch(has -> has.conflictsWith(enchant.getBackend()) || enchant.getBackend().conflictsWith(has))) {
|
||||
this.purge(tier, enchant);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Level generation failed.
|
||||
int level = this.getLevelGenerator().apply(enchant);
|
||||
if (level < enchant.getStartLevel()) {
|
||||
this.purge(tier, enchant);
|
||||
continue;
|
||||
}
|
||||
|
||||
// All good!
|
||||
this.purge(tier, enchant);
|
||||
population.put(enchant.getBackend(), level);
|
||||
enchantsRolled--;
|
||||
}
|
||||
|
||||
return population;
|
||||
}
|
||||
|
||||
public boolean populate() {
|
||||
ItemStack item = this.getItem();
|
||||
AtomicBoolean status = new AtomicBoolean(false);
|
||||
|
||||
var population = this.getPopulation().isEmpty() ? this.createPopulation() : this.getPopulation();
|
||||
|
||||
boolean singleVillagerBook = this.getObtainType() == ObtainType.VILLAGER
|
||||
&& item.getType() == Material.ENCHANTED_BOOK
|
||||
&& Config.ENCHANTMENTS_SINGLE_ENCHANT_IN_VILLAGER_BOOKS.get();
|
||||
|
||||
if (singleVillagerBook) {
|
||||
if (!population.isEmpty()) {
|
||||
EnchantUtils.getAll(item).keySet().forEach(enchantment -> EnchantUtils.remove(item, enchantment));
|
||||
}
|
||||
while (population.size() > 1) {
|
||||
population.remove(Rnd.get(population.keySet()));
|
||||
}
|
||||
}
|
||||
|
||||
population.forEach((enchantment, level) -> {
|
||||
if (EnchantUtils.add(item, enchantment, level, false)) {
|
||||
status.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (status.get()) {
|
||||
EnchantUtils.updateDisplay(item);
|
||||
}
|
||||
|
||||
return status.get();
|
||||
}
|
||||
}
|
@ -0,0 +1,361 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.config;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.utils.Colorizer;
|
||||
import su.nexmedia.engine.utils.StringUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchantsAPI;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
|
||||
import su.nightexpress.excellentenchants.tier.Tier;
|
||||
import su.nightexpress.excellentenchants.tier.TierManager;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class EnchantDefaults {
|
||||
|
||||
private final Map<ObtainType, Double> obtainChance;
|
||||
private final Map<ObtainType, int[]> obtainLevelCap;
|
||||
|
||||
private String displayName;
|
||||
private Tier tier;
|
||||
private List<String> description;
|
||||
private boolean hiddenFromList;
|
||||
private boolean isTreasure;
|
||||
private boolean tradeable;
|
||||
private boolean discoverable;
|
||||
private int levelMin;
|
||||
private int levelMax;
|
||||
private int maxMergeLevel;
|
||||
private EnchantScaler levelByEnchantCost;
|
||||
private EnchantScaler anvilMergeCost;
|
||||
private Set<String> conflicts;
|
||||
private boolean visualEffects;
|
||||
|
||||
private boolean chargesEnabled;
|
||||
private boolean chargesCustomFuel;
|
||||
private EnchantScaler chargesMax;
|
||||
private EnchantScaler chargesConsumeAmount;
|
||||
private EnchantScaler chargesRechargeAmount;
|
||||
private ItemStack chargesFuel;
|
||||
|
||||
public EnchantDefaults(@NotNull ExcellentEnchant enchant) {
|
||||
this.setDisplayName(StringUtil.capitalizeUnderscored(enchant.getId()));
|
||||
this.setTier(0.1);
|
||||
this.setDescription(new ArrayList<>());
|
||||
this.setHiddenFromList(false);
|
||||
this.setTreasure(false);
|
||||
this.setTradeable(true);
|
||||
this.setDiscoverable(true);
|
||||
this.setLevelMin(1);
|
||||
this.setLevelMax(3);
|
||||
this.setMaxMergeLevel(-1);
|
||||
this.setConflicts(new HashSet<>());
|
||||
this.setVisualEffects(true);
|
||||
this.obtainChance = new HashMap<>();
|
||||
this.obtainLevelCap = new HashMap<>();
|
||||
}
|
||||
|
||||
public void load(@NotNull ExcellentEnchant enchant) {
|
||||
ExcellentEnchants plugin = ExcellentEnchantsAPI.PLUGIN;
|
||||
JYML cfg = enchant.getConfig();
|
||||
|
||||
this.setDisplayName(JOption.create("Name", this.getDisplayName(),
|
||||
"Enchantment display name. It will be shown in item lore.").read(cfg));
|
||||
|
||||
Tier tier = plugin.getTierManager().getTierById(JOption.create("Tier", this.getTier().getId(),
|
||||
"Enchantment tier. Must be a valid tier identifier from the '" + TierManager.FILE_NAME + "'.").read(cfg));
|
||||
this.setTier(tier == null ? plugin.getTierManager().getMostCommon() : tier);
|
||||
//this.getTier().getEnchants().add(enchant);
|
||||
|
||||
this.setDescription(JOption.create("Description", this.getDescription(),
|
||||
"Enchantment description. It will be shown in item lore under enchantment name.",
|
||||
"You can use 'Enchantment' placeholders: " + Placeholders.URL_PLACEHOLDERS)
|
||||
.read(cfg));
|
||||
|
||||
this.setHiddenFromList(JOption.create("Hide_From_List", false,
|
||||
"Sets whether or not this enchantment will be hidden from Enchants GUI.").read(cfg));
|
||||
|
||||
this.setTreasure(JOption.create("Is_Treasure", this.isTreasure(),
|
||||
"Sets whether this enchantment is a treasure enchantment.",
|
||||
"Treasure enchantments can only be received via looting, trading, or fishing.").read(cfg));
|
||||
|
||||
if (Config.ENCHANTMENTS_INTERNAL_HANDLER.get()) {
|
||||
this.setTradeable(JOption.create("Tradeable", this.isTradeable(),
|
||||
"Sets whether or not this enchantment can be populated in villager trades.").read(cfg));
|
||||
|
||||
this.setDiscoverable(JOption.create("Discoverable", this.isTradeable(),
|
||||
"Sets whether or not this enchantment can be populated in enchanting table.").read(cfg));
|
||||
}
|
||||
else {
|
||||
this.setTradeable(false);
|
||||
this.setDiscoverable(false);
|
||||
}
|
||||
|
||||
this.setLevelMin(JOption.create("Level.Min", this.getLevelMin(),
|
||||
"Sets the minimal (start) enchantment level. Can not be less than 1.").read(cfg));
|
||||
|
||||
this.setLevelMax(JOption.create("Level.Max", this.getLevelMax(),
|
||||
"Sets the maximal enchantment level. Can not be less than min. level.",
|
||||
"Note: While you can 'bypass' this value by enchant commands, all level-dependant enchantment",
|
||||
"settings will have a limit up to this setting.").read(cfg));
|
||||
|
||||
this.setMaxMergeLevel(JOption.create("Anvil.Max_Merge_Level", this.getMaxMergeLevel(),
|
||||
"Sets max. enchantment level that can be obtained by combining 2 items with this enchantment.",
|
||||
"Set this to '-1' to remove merge limit and just use 'Max Level' instead."
|
||||
).read(cfg));
|
||||
|
||||
this.setLevelByEnchantCost(EnchantScaler.read(enchant, ObtainType.ENCHANTING.getPathName() + ".Level_By_Exp_Cost",
|
||||
(int)(30D / this.levelMax) + " * " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Sets how much XP levels must be used in enchanting table to obtain this enchantment.",
|
||||
"With a default formula '9 * %enchantment_level%' it will be [9, 18, 27] XP levels for [1, 2, 3] enchantment levels."));
|
||||
|
||||
this.setAnvilMergeCost(EnchantScaler.read(enchant, "Anvil.Merge_Cost", Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Sets how much XP levels will be added to the anvil cost when combining custom enchantments."));
|
||||
|
||||
for (ObtainType obtainType : ObtainType.values()) {
|
||||
double obtainChance = JOption.create(obtainType.getPathName() + ".Chance", 50D,
|
||||
"Chance for this enchantment to be obtained via " + obtainType.getPathName()).read(cfg);
|
||||
this.getObtainChance().put(obtainType, obtainChance);
|
||||
|
||||
int levelMin = JOption.create(obtainType.getPathName() + ".Level.Min", -1,
|
||||
"Minimal level when obtained via " + obtainType.getPathName(),
|
||||
"Can not be less than enchantment min. level. Set -1 to use enchantment min. level.").read(cfg);
|
||||
int levelMax = JOption.create(obtainType.getPathName() + ".Level.Max", -1,
|
||||
"Maximal level when obtained via " + obtainType.getPathName(),
|
||||
"Can not be greater than enchantment max. level. Set -1 to use enchantment max. level.").read(cfg);
|
||||
this.getObtainLevelCap().put(obtainType, new int[]{levelMin, levelMax});
|
||||
}
|
||||
|
||||
|
||||
this.setConflicts(JOption.create("Conflicts", this.getConflicts(),
|
||||
"A list of conflicting enchantment names.",
|
||||
"Conflicting enchantments can not be combined on anvils and obtained together on the same item.").read(cfg));
|
||||
|
||||
this.setVisualEffects(JOption.create("Settings.Visual_Effects", this.isVisualEffects(),
|
||||
"Enables/Disables enchantment visual effects, such as particles.").read(cfg));
|
||||
|
||||
|
||||
if (Config.ENCHANTMENTS_CHARGES_ENABLED.get()) {
|
||||
this.setChargesEnabled(JOption.create("Settings.Charges.Enabled", this.isChargesEnabled(),
|
||||
"When 'true' enables the Charges system for this enchantment.",
|
||||
"When enchanted the first time on enchanting table, it will have maximum charges amount.").read(cfg));
|
||||
|
||||
this.setChargesCustomFuel(JOption.create("Settings.Charges.Custom_Fuel", this.isChargesCustomFuel(),
|
||||
"When 'true' uses different (non-default) fuel item (from the 'Fuel_Item' setting) to recharge.").read(cfg));
|
||||
|
||||
this.setChargesMax(EnchantScaler.read(enchant, "Settings.Charges.Maximum", "100",
|
||||
"Maximum amount of charges for the enchantment."));
|
||||
|
||||
this.setChargesConsumeAmount(EnchantScaler.read(enchant, "Settings.Charges.Consume_Amount", "1",
|
||||
"How many charges will be consumed when enchantment is triggered?"));
|
||||
|
||||
this.setChargesRechargeAmount(EnchantScaler.read(enchant, "Settings.Charges.Recharge_Amount", "25",
|
||||
"How many charges will be restored when using 'Fuel Item' in anvil?"));
|
||||
|
||||
this.setChargesFuel(JOption.create("Settings.Charges.Fuel_Item", new ItemStack(Material.LAPIS_LAZULI),
|
||||
"An item, that will be used to restore enchantment charges on anvils.",
|
||||
"Item Options:" + Placeholders.URL_ENGINE_ITEMS)
|
||||
.setWriter(JYML::setItem).read(cfg));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(@NotNull String displayName) {
|
||||
this.displayName = Colorizer.apply(displayName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Tier getTier() {
|
||||
return tier;
|
||||
}
|
||||
|
||||
public void setTier(double rarity) {
|
||||
this.setTier(ExcellentEnchantsAPI.getTierManager().getByRarityModifier(rarity));
|
||||
}
|
||||
|
||||
public void setTier(@NotNull Tier tier) {
|
||||
this.tier = tier;
|
||||
}
|
||||
|
||||
public void setDescription(@NotNull String... description) {
|
||||
this.setDescription(Arrays.asList(description));
|
||||
}
|
||||
|
||||
public void setDescription(@NotNull List<String> description) {
|
||||
this.description = Colorizer.apply(description);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean isHiddenFromList() {
|
||||
return hiddenFromList;
|
||||
}
|
||||
|
||||
public void setHiddenFromList(boolean hiddenFromList) {
|
||||
this.hiddenFromList = hiddenFromList;
|
||||
}
|
||||
|
||||
public boolean isTreasure() {
|
||||
return isTreasure;
|
||||
}
|
||||
|
||||
public void setTreasure(boolean treasure) {
|
||||
isTreasure = treasure;
|
||||
}
|
||||
|
||||
public boolean isTradeable() {
|
||||
return tradeable;
|
||||
}
|
||||
|
||||
public void setTradeable(boolean tradeable) {
|
||||
this.tradeable = tradeable;
|
||||
}
|
||||
|
||||
public boolean isDiscoverable() {
|
||||
return discoverable;
|
||||
}
|
||||
|
||||
public void setDiscoverable(boolean discoverable) {
|
||||
this.discoverable = discoverable;
|
||||
}
|
||||
|
||||
public void setLevelMin(int levelMin) {
|
||||
this.levelMin = Math.max(1, levelMin);
|
||||
}
|
||||
|
||||
public int getLevelMin() {
|
||||
return levelMin;
|
||||
}
|
||||
|
||||
public void setLevelMax(int levelMax) {
|
||||
this.levelMax = Math.max(1, levelMax);
|
||||
}
|
||||
|
||||
public int getLevelMax() {
|
||||
return levelMax;
|
||||
}
|
||||
|
||||
public int getMaxMergeLevel() {
|
||||
return this.maxMergeLevel;
|
||||
}
|
||||
|
||||
public void setMaxMergeLevel(int maxMergeLevel) {
|
||||
this.maxMergeLevel = Math.min(this.getLevelMax(), maxMergeLevel);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantScaler getLevelByEnchantCost() {
|
||||
return levelByEnchantCost;
|
||||
}
|
||||
|
||||
public void setLevelByEnchantCost(@NotNull EnchantScaler levelByEnchantCost) {
|
||||
this.levelByEnchantCost = levelByEnchantCost;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantScaler getAnvilMergeCost() {
|
||||
return anvilMergeCost;
|
||||
}
|
||||
|
||||
public void setAnvilMergeCost(@NotNull EnchantScaler anvilMergeCost) {
|
||||
this.anvilMergeCost = anvilMergeCost;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<ObtainType, Double> getObtainChance() {
|
||||
return obtainChance;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<ObtainType, int[]> getObtainLevelCap() {
|
||||
return obtainLevelCap;
|
||||
}
|
||||
|
||||
public void setConflicts(@NotNull String... conflicts) {
|
||||
this.setConflicts(new HashSet<>(Arrays.asList(conflicts)));
|
||||
}
|
||||
|
||||
public void setConflicts(@NotNull Set<String> conflicts) {
|
||||
this.conflicts = conflicts;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<String> getConflicts() {
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
public boolean isVisualEffects() {
|
||||
return visualEffects;
|
||||
}
|
||||
|
||||
public void setVisualEffects(boolean visualEffects) {
|
||||
this.visualEffects = visualEffects;
|
||||
}
|
||||
|
||||
public boolean isChargesEnabled() {
|
||||
return chargesEnabled;
|
||||
}
|
||||
|
||||
public void setChargesEnabled(boolean chargesEnabled) {
|
||||
this.chargesEnabled = chargesEnabled;
|
||||
}
|
||||
|
||||
public boolean isChargesCustomFuel() {
|
||||
return chargesCustomFuel;
|
||||
}
|
||||
|
||||
public void setChargesCustomFuel(boolean chargesCustomFuel) {
|
||||
this.chargesCustomFuel = chargesCustomFuel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantScaler getChargesMax() {
|
||||
return chargesMax;
|
||||
}
|
||||
|
||||
public void setChargesMax(@NotNull EnchantScaler chargesMax) {
|
||||
this.chargesMax = chargesMax;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ItemStack getChargesFuel() {
|
||||
return chargesFuel;
|
||||
}
|
||||
|
||||
public void setChargesFuel(@Nullable ItemStack chargesFuel) {
|
||||
this.chargesFuel = chargesFuel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantScaler getChargesConsumeAmount() {
|
||||
return chargesConsumeAmount;
|
||||
}
|
||||
|
||||
public void setChargesConsumeAmount(@NotNull EnchantScaler chargesConsumeAmount) {
|
||||
this.chargesConsumeAmount = chargesConsumeAmount;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantScaler getChargesRechargeAmount() {
|
||||
return chargesRechargeAmount;
|
||||
}
|
||||
|
||||
public void setChargesRechargeAmount(@NotNull EnchantScaler chargesRechargeAmount) {
|
||||
this.chargesRechargeAmount = chargesRechargeAmount;
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.config;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.utils.Evaluator;
|
||||
import su.nexmedia.engine.utils.StringUtil;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class EnchantScaler {
|
||||
|
||||
public EnchantScaler(@NotNull ExcellentEnchant enchant, @NotNull String path) {
|
||||
this(enchant.getConfig(), path, Placeholders.ENCHANTMENT_LEVEL, enchant.getStartLevel(), enchant.getMaxLevel());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static EnchantScaler read(@NotNull ExcellentEnchant enchant, @NotNull String path, @NotNull String def, @Nullable String... comments) {
|
||||
enchant.getConfig().addMissing(path, def);
|
||||
if (comments != null) {
|
||||
List<String> list = new ArrayList<>(Arrays.asList(comments));
|
||||
list.add("You can use formulas/expressions here: " + Placeholders.URL_ENGINE_SCALER);
|
||||
list.add("Level placeholder: " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
enchant.getConfig().setComments(path, list);
|
||||
}
|
||||
return new EnchantScaler(enchant, path);
|
||||
}
|
||||
|
||||
private final int levelMin;
|
||||
private final int levelMax;
|
||||
private final TreeMap<Integer, Double> values;
|
||||
|
||||
public EnchantScaler(@NotNull JYML cfg, @NotNull String path, @NotNull String levelPlaceholder, int levelMin, int levelMax) {
|
||||
this.levelMin = levelMin;
|
||||
this.levelMax = levelMax;
|
||||
this.values = new TreeMap<>();
|
||||
|
||||
// Load different values for each object level.
|
||||
Set<String> lvlKeys = cfg.getSection(path);
|
||||
if (!lvlKeys.isEmpty()) {
|
||||
for (String sLvl : lvlKeys) {
|
||||
int eLvl = StringUtil.getInteger(sLvl, 0);
|
||||
if (eLvl < this.getLevelMin() || eLvl > this.getLevelMax()) continue;
|
||||
|
||||
String formula = cfg.getString(path + "." + sLvl, "0").replace(levelPlaceholder, sLvl);
|
||||
values.put(eLvl, Evaluator.evaluate(formula));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the single formula for all object levels.
|
||||
for (int lvl = this.getLevelMin(); lvl < (this.getLevelMax() + 1); lvl++) {
|
||||
String sLvl = String.valueOf(lvl);
|
||||
String exChance = cfg.getString(path, "").replace(levelPlaceholder, sLvl);
|
||||
if (exChance.isEmpty()) continue;
|
||||
|
||||
values.put(lvl, Evaluator.evaluate(exChance));
|
||||
}
|
||||
}
|
||||
|
||||
public int getLevelMin() {
|
||||
return this.levelMin;
|
||||
}
|
||||
|
||||
public int getLevelMax() {
|
||||
return this.levelMax;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TreeMap<Integer, Double> getValues() {
|
||||
return this.values;
|
||||
}
|
||||
|
||||
public double getValue(int level) {
|
||||
Map.Entry<Integer, Double> en = this.values.floorEntry(level);
|
||||
return en != null ? en.getValue() : 0D;
|
||||
}
|
||||
}
|
@ -0,0 +1,459 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nexmedia.engine.api.placeholder.PlaceholderMap;
|
||||
import su.nexmedia.engine.lang.LangManager;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.IEnchantment;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Periodic;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantDefaults;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ObtainType;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
import su.nightexpress.excellentenchants.tier.Tier;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class ExcellentEnchant /*extends Enchantment*/ implements IEnchantment {
|
||||
|
||||
protected final ExcellentEnchants plugin;
|
||||
protected final JYML cfg;
|
||||
protected final String id;
|
||||
protected final EnchantDefaults defaults;
|
||||
protected final NamespacedKey chargesKey;
|
||||
protected final Map<Integer, PlaceholderMap> placeholdersMap;
|
||||
|
||||
public ExcellentEnchant(@NotNull ExcellentEnchants plugin, @NotNull String id) {
|
||||
//super(NamespacedKey.minecraft(id.toLowerCase()));
|
||||
this.plugin = plugin;
|
||||
this.id = id.toLowerCase();//this.getKey().getKey();
|
||||
this.cfg = new JYML(plugin.getDataFolder() + EnchantManager.DIR_ENCHANTS, id + ".yml");
|
||||
this.chargesKey = new NamespacedKey(plugin, this.getId() + ".charges");
|
||||
this.defaults = new EnchantDefaults(this);
|
||||
this.placeholdersMap = new HashMap<>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return EnchantUtils.createKey(this.getId());
|
||||
}
|
||||
|
||||
public void loadSettings() {
|
||||
this.cfg.reload();
|
||||
this.placeholdersMap.clear();
|
||||
|
||||
this.getDefaults().load(this);
|
||||
|
||||
for (int i = this.getStartLevel(); i < this.getMaxLevel() + 1; i++) {
|
||||
int level = i;
|
||||
|
||||
PlaceholderMap map = new PlaceholderMap()
|
||||
.add(Placeholders.ENCHANTMENT_DESCRIPTION, () -> String.join("\n", this.getDescription()))
|
||||
.add(Placeholders.ENCHANTMENT_ID, this::getId)
|
||||
.add(Placeholders.ENCHANTMENT_NAME, this::getDisplayName)
|
||||
.add(Placeholders.ENCHANTMENT_NAME_FORMATTED, () -> this.getNameFormatted(level))
|
||||
.add(Placeholders.ENCHANTMENT_LEVEL, () -> NumberUtil.toRoman(level))
|
||||
.add(Placeholders.ENCHANTMENT_LEVEL_MIN, () -> String.valueOf(this.getStartLevel()))
|
||||
.add(Placeholders.ENCHANTMENT_LEVEL_MAX, () -> String.valueOf(this.getMaxLevel()))
|
||||
.add(Placeholders.ENCHANTMENT_TIER, () -> this.getTier().getName())
|
||||
.add(Placeholders.ENCHANTMENT_TIER_COLOR, () -> this.getTier().getColor())
|
||||
.add(Placeholders.ENCHANTMENT_FIT_ITEM_TYPES, () -> {
|
||||
if (this.getFitItemTypes().length == 0) return plugin.getLangManager().getEnum(this.getCategory());
|
||||
|
||||
return String.join(", ", Stream.of(this.getFitItemTypes()).map(type -> plugin.getLangManager().getEnum(type)).toList());
|
||||
})
|
||||
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING, () -> NumberUtil.format(this.getObtainChance(ObtainType.ENCHANTING)))
|
||||
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_VILLAGER, () -> NumberUtil.format(this.getObtainChance(ObtainType.VILLAGER)))
|
||||
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_LOOT_GENERATION, () -> NumberUtil.format(this.getObtainChance(ObtainType.LOOT_GENERATION)))
|
||||
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_FISHING, () -> NumberUtil.format(this.getObtainChance(ObtainType.FISHING)))
|
||||
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_MOB_SPAWNING, () -> NumberUtil.format(this.getObtainChance(ObtainType.MOB_SPAWNING)))
|
||||
.add(Placeholders.ENCHANTMENT_CHARGES_MAX_AMOUNT, () -> NumberUtil.format(this.getChargesMax(level)))
|
||||
.add(Placeholders.ENCHANTMENT_CHARGES_CONSUME_AMOUNT, () -> NumberUtil.format(this.getChargesConsumeAmount(level)))
|
||||
.add(Placeholders.ENCHANTMENT_CHARGES_RECHARGE_AMOUNT, () -> NumberUtil.format(this.getChargesRechargeAmount(level)))
|
||||
.add(Placeholders.ENCHANTMENT_CHARGES_FUEL_ITEM, () -> ItemUtil.getItemName(this.getChargesFuel()));
|
||||
|
||||
if (this instanceof Chanced chanced) {
|
||||
map.add(Placeholders.ENCHANTMENT_CHANCE, () -> NumberUtil.format(chanced.getTriggerChance(level)));
|
||||
}
|
||||
if (this instanceof Periodic periodic) {
|
||||
map.add(Placeholders.ENCHANTMENT_INTERVAL, () -> NumberUtil.format(periodic.getInterval() / 20D));
|
||||
}
|
||||
if (this instanceof Potioned potioned) {
|
||||
map.add(Placeholders.ENCHANTMENT_POTION_LEVEL, () -> NumberUtil.toRoman(potioned.getEffectAmplifier(level)));
|
||||
map.add(Placeholders.ENCHANTMENT_POTION_DURATION, () -> NumberUtil.format(potioned.getEffectDuration(level) / 20D));
|
||||
map.add(Placeholders.ENCHANTMENT_POTION_TYPE, () -> LangManager.getPotionType(potioned.getEffectType()));
|
||||
}
|
||||
map.add(this.getTier().getPlaceholders());
|
||||
|
||||
this.placeholdersMap.put(level, map);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PlaceholderMap getPlaceholders(int level) {
|
||||
if (level > this.getMaxLevel()) level = this.getMaxLevel();
|
||||
if (level < this.getStartLevel()) level = this.getStartLevel();
|
||||
|
||||
return this.placeholdersMap.get(level);
|
||||
}
|
||||
|
||||
public void addPlaceholder(@NotNull String key, @NotNull Function<Integer, String> replacer) {
|
||||
for (int level = this.getStartLevel(); level < this.getMaxLevel() + 1; level++) {
|
||||
this.getPlaceholders(level).add(key, replacer.apply(level));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerListeners() {
|
||||
if (this instanceof EventListener listener) {
|
||||
this.plugin.getPluginManager().registerEvents(listener, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
//FitItemType itemType = FitItemType.getByEnchantmentTarget(this.getCategory());
|
||||
//return new FitItemType[]{itemType};
|
||||
|
||||
return new ItemCategory[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public EquipmentSlot[] getSlots() {
|
||||
return switch (this.getCategory()) {
|
||||
case BOW, CROSSBOW, TRIDENT, FISHING_ROD, WEAPON, TOOL -> new EquipmentSlot[]{EquipmentSlot.HAND};
|
||||
case ARMOR_HEAD -> new EquipmentSlot[]{EquipmentSlot.HEAD};
|
||||
case ARMOR_TORSO -> new EquipmentSlot[]{EquipmentSlot.CHEST};
|
||||
case ARMOR_LEGS -> new EquipmentSlot[]{EquipmentSlot.LEGS};
|
||||
case ARMOR_FEET -> new EquipmentSlot[]{EquipmentSlot.FEET};
|
||||
case ARMOR, WEARABLE -> new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
|
||||
case BREAKABLE -> new EquipmentSlot[]{EquipmentSlot.HAND, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
|
||||
case VANISHABLE -> EquipmentSlot.values();
|
||||
default -> throw new IllegalStateException("Unexpected value: " + this.getCategory());
|
||||
};
|
||||
|
||||
/*Set<EquipmentSlot> slots = new HashSet<>();
|
||||
|
||||
for (FitItemType itemType : this.getFitItemTypes()) {
|
||||
slots.addAll(Arrays.asList(itemType.getSlots()));
|
||||
}
|
||||
|
||||
return slots.toArray(new EquipmentSlot[0]);*/
|
||||
}
|
||||
|
||||
public boolean isDisabledInWorld(@NotNull World world) {
|
||||
Set<String> disabled = Config.ENCHANTMENTS_DISABLED_IN_WORLDS.get().getOrDefault(world.getName(), Collections.emptySet());
|
||||
return disabled.contains(this.getKey().getKey()) || disabled.contains(Placeholders.WILDCARD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailableToUse(@NotNull LivingEntity entity) {
|
||||
return !this.isDisabledInWorld(entity.getWorld());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JYML getConfig() {
|
||||
return this.cfg;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EnchantDefaults getDefaults() {
|
||||
return defaults;
|
||||
}
|
||||
|
||||
/*@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getId().toUpperCase();
|
||||
}*/
|
||||
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return this.getDefaults().getDisplayName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getNameFormatted(int level) {
|
||||
String name = this.getTier().getColor() + this.getDisplayName();
|
||||
if (level > 1 || this.getMaxLevel() > 1) {
|
||||
name += " " + NumberUtil.toRoman(level);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getNameFormatted(int level, int charges) {
|
||||
if (!this.isChargesEnabled() || charges < 0) return this.getNameFormatted(level);
|
||||
|
||||
int chargesMax = this.getChargesMax(level);
|
||||
int percent = (int) Math.ceil((double) charges / (double) chargesMax * 100D);
|
||||
Map.Entry<Integer, String> entry = Config.ENCHANTMENTS_CHARGES_FORMAT.get().floorEntry(percent);
|
||||
if (entry == null) return this.getNameFormatted(level);
|
||||
|
||||
String format = entry.getValue().replace(Placeholders.GENERIC_AMOUNT, String.valueOf(charges));
|
||||
return this.getNameFormatted(level) + " " + format;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getDescription() {
|
||||
return this.getDefaults().getDescription();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getDescription(int level) {
|
||||
List<String> description = new ArrayList<>(this.getDescription());
|
||||
description.replaceAll(this.getPlaceholders(level).replacer());
|
||||
return description;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> formatDescription() {
|
||||
return new ArrayList<>(this.getDescription().stream()
|
||||
.map(line -> Config.ENCHANTMENTS_DESCRIPTION_FORMAT.get().replace(Placeholders.GENERIC_DESCRIPTION, line))
|
||||
.toList());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> formatDescription(int level) {
|
||||
return new ArrayList<>(this.getDescription(level).stream()
|
||||
.map(line -> Config.ENCHANTMENTS_DESCRIPTION_FORMAT.get().replace(Placeholders.GENERIC_DESCRIPTION, line))
|
||||
.toList());
|
||||
}
|
||||
|
||||
public boolean hasConflicts() {
|
||||
return !this.getConflicts().isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<String> getConflicts() {
|
||||
return this.getDefaults().getConflicts();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Tier getTier() {
|
||||
return this.getDefaults().getTier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLevel() {
|
||||
return this.getDefaults().getLevelMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartLevel() {
|
||||
return this.getDefaults().getLevelMin();
|
||||
}
|
||||
|
||||
public int getMaxMergeLevel() {
|
||||
return this.getDefaults().getMaxMergeLevel() < 0 ? this.getMaxLevel() : this.getDefaults().getMaxMergeLevel();
|
||||
}
|
||||
|
||||
public int getLevelByEnchantCost(int expLevel) {
|
||||
int get = this.getDefaults().getLevelByEnchantCost().getValues().entrySet().stream()
|
||||
.filter(en -> expLevel >= en.getValue().intValue()).max(Comparator.comparingInt(Map.Entry::getKey))
|
||||
.map(Map.Entry::getKey).orElse(0);
|
||||
|
||||
return get != 0 ? this.fineLevel(get, ObtainType.ENCHANTING) : 0;
|
||||
}
|
||||
|
||||
public boolean isObtainable(@NotNull ObtainType obtainType) {
|
||||
if (obtainType == ObtainType.ENCHANTING && (this.isTreasure() || this.isCurse())) return false;
|
||||
|
||||
return this.getObtainChance(obtainType) > 0D;
|
||||
}
|
||||
|
||||
public double getObtainChance(@NotNull ObtainType obtainType) {
|
||||
return this.getDefaults().getObtainChance().getOrDefault(obtainType, 0D);
|
||||
}
|
||||
|
||||
public int getObtainLevelMin(@NotNull ObtainType obtainType) {
|
||||
return this.getDefaults().getObtainLevelCap().getOrDefault(obtainType, new int[]{-1, -1})[0];
|
||||
}
|
||||
|
||||
public int getObtainLevelMax(@NotNull ObtainType obtainType) {
|
||||
return this.getDefaults().getObtainLevelCap().getOrDefault(obtainType, new int[]{-1, -1})[1];
|
||||
}
|
||||
|
||||
public int fineLevel(int level, @NotNull ObtainType obtainType) {
|
||||
int levelCapMin = this.getObtainLevelMin(obtainType);
|
||||
int levelCapMax = this.getObtainLevelMax(obtainType);
|
||||
|
||||
if (levelCapMin > 0 && level < levelCapMin) level = levelCapMin;
|
||||
if (levelCapMax > 0 && level > levelCapMax) level = levelCapMax;
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
public int generateLevel() {
|
||||
return Rnd.get(this.getStartLevel(), this.getMaxLevel());
|
||||
}
|
||||
|
||||
public int generateLevel(@NotNull ObtainType obtainType) {
|
||||
int levelCapMin = this.getObtainLevelMin(obtainType);
|
||||
int levelCapMax = this.getObtainLevelMax(obtainType);
|
||||
|
||||
if (levelCapMin <= 0 || levelCapMin < this.getStartLevel()) levelCapMin = this.getStartLevel();
|
||||
if (levelCapMax <= 0 || levelCapMax > this.getMaxLevel()) levelCapMax = this.getMaxLevel();
|
||||
|
||||
return Rnd.get(levelCapMin, levelCapMax);
|
||||
}
|
||||
|
||||
public int getAnvilMergeCost(int level) {
|
||||
return (int) this.getDefaults().getAnvilMergeCost().getValue(level);
|
||||
}
|
||||
|
||||
/*@Override
|
||||
@Deprecated
|
||||
public final boolean conflictsWith(@NotNull Enchantment enchantment) {
|
||||
return this.getConflicts().contains(enchantment.getKey().getKey());
|
||||
}*/
|
||||
|
||||
@Deprecated
|
||||
public Enchantment getBackend() {
|
||||
return EnchantUtils.getEnchantment(this.getKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean checkEnchantCategory(@NotNull ItemStack item) {
|
||||
EnchantmentTarget category = this.getCategory();
|
||||
|
||||
if (category == EnchantmentTarget.WEAPON && ItemUtil.isAxe(item)) {
|
||||
return Config.ENCHANTMENTS_ITEM_SWORD_ENCHANTS_TO_AXES.get();
|
||||
}
|
||||
if (category == EnchantmentTarget.BOW && item.getType() == Material.CROSSBOW) {
|
||||
return Config.ENCHANTMENTS_ITEM_BOW_ENCHANTS_TO_CROSSBOW.get();
|
||||
}
|
||||
if ((category == EnchantmentTarget.ARMOR || category == EnchantmentTarget.ARMOR_TORSO) && item.getType() == Material.ELYTRA) {
|
||||
return Config.ENCHANTMENTS_ITEM_CHESTPLATE_ENCHANTS_TO_ELYTRA.get();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkItemCategory(@NotNull ItemStack item) {
|
||||
ItemCategory[] itemCategories = this.getFitItemTypes();
|
||||
if (itemCategories.length == 0) return false;
|
||||
|
||||
return Stream.of(itemCategories).anyMatch(itemCategory -> itemCategory.isIncluded(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurse() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isTreasure() {
|
||||
return this.getDefaults().isTreasure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTradeable() {
|
||||
return this.getDefaults().isTradeable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDiscoverable() {
|
||||
return this.getDefaults().isDiscoverable();
|
||||
}
|
||||
|
||||
public boolean hasVisualEffects() {
|
||||
return this.getDefaults().isVisualEffects();
|
||||
}
|
||||
|
||||
public boolean isChargesEnabled() {
|
||||
return Config.ENCHANTMENTS_CHARGES_ENABLED.get() && this.getDefaults().isChargesEnabled();
|
||||
}
|
||||
|
||||
public boolean isChargesCustomFuel() {
|
||||
return this.getDefaults().isChargesCustomFuel();
|
||||
}
|
||||
|
||||
public int getChargesMax(int level) {
|
||||
return this.isChargesEnabled() ? (int) this.getDefaults().getChargesMax().getValue(level) : 0;
|
||||
}
|
||||
|
||||
public int getChargesConsumeAmount(int level) {
|
||||
return this.isChargesEnabled() ? (int) this.getDefaults().getChargesConsumeAmount().getValue(level) : 0;
|
||||
}
|
||||
|
||||
public int getChargesRechargeAmount(int level) {
|
||||
return this.isChargesEnabled() ? (int) this.getDefaults().getChargesRechargeAmount().getValue(level) : 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getChargesFuel() {
|
||||
ItemStack fuelHas = this.getDefaults().getChargesFuel();
|
||||
if (!this.isChargesCustomFuel() || fuelHas == null || fuelHas.getType().isAir()) {
|
||||
return Config.ENCHANTMENTS_CHARGES_FUEL_ITEM.get();
|
||||
}
|
||||
return new ItemStack(fuelHas);
|
||||
}
|
||||
|
||||
public boolean isChargesFuel(@NotNull ItemStack item) {
|
||||
if (Config.ENCHANTMENTS_CHARGES_COMPARE_TYPE_ONLY.get()) {
|
||||
return item.getType() == this.getChargesFuel().getType();
|
||||
}
|
||||
return item.isSimilar(this.getChargesFuel());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamespacedKey getChargesKey() {
|
||||
return chargesKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutOfCharges(@NotNull ItemStack item) {
|
||||
return EnchantUtils.isOutOfCharges(item, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullOfCharges(@NotNull ItemStack item) {
|
||||
return EnchantUtils.isFullOfCharges(item, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharges(@NotNull ItemStack item) {
|
||||
return EnchantUtils.getCharges(item, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consumeChargesNoUpdate(@NotNull ItemStack item, int level) {
|
||||
if (!this.isChargesEnabled()) return;
|
||||
|
||||
EnchantUtils.consumeCharges(item, this, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consumeCharges(@NotNull ItemStack item, int level) {
|
||||
if (!this.isChargesEnabled()) return;
|
||||
|
||||
this.consumeChargesNoUpdate(item, level);
|
||||
EnchantUtils.updateDisplay(item);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class AquamanEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
|
||||
|
||||
public static final String ID = "aquaman";
|
||||
|
||||
private PotionImplementation potionImplementation;
|
||||
private PeriodImplementation periodImplementation;
|
||||
|
||||
public AquamanEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.4);
|
||||
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.WATER_BREATHING, true);
|
||||
this.periodImplementation = PeriodImplementation.create(this, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PeriodImplementation getPeriodImplementation() {
|
||||
return periodImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_HEAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class ColdSteelEnchant extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
|
||||
|
||||
public static final String ID = "cold_steel";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public ColdSteelEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to apply " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
|
||||
this.getDefaults().setTier(0.3);
|
||||
this.getDefaults().setLevelMax(3);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"60 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.SLOW_DIGGING, false,
|
||||
"4 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getProtectPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
return this.addEffect(damager, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class DarknessCloakEnchant extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
|
||||
|
||||
public static final String ID = "darkness_cloak";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public DarknessCloakEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to apply " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"20.0 * " + Placeholders.ENCHANTMENT_LEVEL + " * 0.75");
|
||||
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.DARKNESS, false,
|
||||
"2.5" + Placeholders.ENCHANTMENT_LEVEL,
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getProtectPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.addEffect(damager, level)) return false;
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.of(Particle.ASH).play(damager.getEyeLocation(), 0.75, 0.1, 30);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class ElementalProtectionEnchant extends ExcellentEnchant implements GenericEnchant, EventListener {
|
||||
|
||||
public static final String ID = "elemental_protection";
|
||||
public static final String PLACEHOLDER_PROTECTION_AMOUNT = "%enchantment_protection_amount%";
|
||||
public static final String PLACEHOLDER_PROTECTION_CAPACITY = "%enchantment_protection_capacity%";
|
||||
|
||||
private static final Set<EntityDamageEvent.DamageCause> DAMAGE_CAUSES = Set.of(
|
||||
EntityDamageEvent.DamageCause.POISON, EntityDamageEvent.DamageCause.WITHER,
|
||||
EntityDamageEvent.DamageCause.MAGIC, EntityDamageEvent.DamageCause.FREEZE,
|
||||
EntityDamageEvent.DamageCause.LIGHTNING);
|
||||
|
||||
private EnchantScaler protectionAmount;
|
||||
private double protectionCapacity;
|
||||
private boolean protectionAsModifier;
|
||||
|
||||
public ElementalProtectionEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Reduces Poison, Magic, Wither, Lightning, Freeze damage by " + PLACEHOLDER_PROTECTION_AMOUNT + ".");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.protectionAmount = EnchantScaler.read(this, "Settings.Protection.Amount",
|
||||
"0.05 * " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"How protection the enchantment will have?");
|
||||
this.protectionCapacity = JOption.create("Settings.Protection.Capacity", 1D,
|
||||
"Maximal possible protection value from all armor pieces together.").read(cfg);
|
||||
this.protectionAsModifier = JOption.create("Settings.Protection.As_Modifier", false,
|
||||
"When 'true' damage will be reduced by a percent of protection value.",
|
||||
"When 'false' damage will be reduced by a plain protection value.").read(cfg);
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_PROTECTION_AMOUNT, level -> NumberUtil.format(this.getProtectionAmount(level)));
|
||||
this.addPlaceholder(PLACEHOLDER_PROTECTION_CAPACITY, level -> NumberUtil.format(this.getProtectionCapacity()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR;
|
||||
}
|
||||
|
||||
public double getProtectionAmount(int level) {
|
||||
return this.protectionAmount.getValue(level);
|
||||
}
|
||||
|
||||
public double getProtectionCapacity() {
|
||||
return this.protectionCapacity;
|
||||
}
|
||||
|
||||
public boolean isProtectionAsModifier() {
|
||||
return this.protectionAsModifier;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onDamage(EntityDamageEvent event) {
|
||||
if (!DAMAGE_CAUSES.contains(event.getCause())) return;
|
||||
if (!(event.getEntity() instanceof LivingEntity entity)) return;
|
||||
if (!this.isAvailableToUse(entity)) return;
|
||||
|
||||
double protectionAmount = 0D;
|
||||
for (ItemStack armor : EnchantUtils.getEnchantedEquipment(entity).values()) {
|
||||
int level = EnchantUtils.getLevel(armor, this.getBackend());
|
||||
if (level <= 0) continue;
|
||||
|
||||
protectionAmount += this.getProtectionAmount(level);
|
||||
this.consumeCharges(armor, level);
|
||||
}
|
||||
|
||||
if (protectionAmount <= 0D) return;
|
||||
if (protectionAmount > this.getProtectionCapacity()) {
|
||||
protectionAmount = this.getProtectionCapacity();
|
||||
}
|
||||
|
||||
if (this.isProtectionAsModifier()) {
|
||||
event.setDamage(Math.max(0, event.getDamage() * (1D - protectionAmount)));
|
||||
}
|
||||
else {
|
||||
event.setDamage(Math.max(0, event.getDamage() - protectionAmount));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class FireShieldEnchant extends ExcellentEnchant implements Chanced, CombatEnchant {
|
||||
|
||||
public static final String ID = "fire_shield";
|
||||
public static final String PLACEHOLDER_FIRE_DURATION = "%enchantment_fire_duration%";
|
||||
|
||||
private EnchantScaler fireDuration;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public FireShieldEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to ignite the attacker for " + PLACEHOLDER_FIRE_DURATION + "s.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
Placeholders.ENCHANTMENT_LEVEL + " * 15.0");
|
||||
this.fireDuration = EnchantScaler.read(this, "Settings.Fire.Duration",
|
||||
"2.5 * " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Sets the fire duration (in seconds).",
|
||||
"If entity's current fire ticks amount is less than this value, it will be set to this value.",
|
||||
"If entity's current fire ticks amount is greater than this value, it won't be changed.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_FIRE_DURATION, level -> NumberUtil.format(this.getFireDuration(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getProtectPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
public double getFireDuration(int level) {
|
||||
return this.fireDuration.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event,
|
||||
@NotNull LivingEntity damager, @NotNull LivingEntity victim,
|
||||
@NotNull ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
int ticksToSet = (int) (this.getFireDuration(level) * 20);
|
||||
int ticksHas = damager.getFireTicks();
|
||||
if (ticksHas >= ticksToSet) return false;
|
||||
|
||||
damager.setFireTicks(ticksToSet);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
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.block.BlockExplodeEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.Version;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nexmedia.engine.api.server.AbstractTask;
|
||||
import su.nexmedia.engine.utils.Pair;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.Cleanable;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FlameWalkerEnchant extends ExcellentEnchant implements GenericEnchant, EventListener, Cleanable {
|
||||
|
||||
public static final String ID = "flame_walker";
|
||||
|
||||
private static final BlockFace[] FACES = {BlockFace.SOUTH, BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST};
|
||||
private static final Map<Block, Pair<Long, Integer>> BLOCKS_TO_DESTROY = new ConcurrentHashMap<>();
|
||||
|
||||
private EnchantScaler blockDecayTime;
|
||||
private BlockTickTask blockTickTask;
|
||||
|
||||
public FlameWalkerEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Ability to walk on lava and magma blocks without getting damage.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.7);
|
||||
this.getDefaults().getConflicts().add(Enchantment.FROST_WALKER.getKey().getKey());
|
||||
|
||||
this.blockTickTask = new BlockTickTask(plugin);
|
||||
this.blockTickTask.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.blockDecayTime = EnchantScaler.read(this, "Settings.Block_Decay", "12.0",
|
||||
"Sets up to how long (in seconds) blocks will stay before turn back to lava.");
|
||||
}
|
||||
|
||||
@Override
|
||||
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, Pair.of(System.currentTimeMillis() + (long) seconds * 1000L, Rnd.get(100)));
|
||||
}
|
||||
|
||||
public static boolean isBlock(@NotNull Block block) {
|
||||
return BLOCKS_TO_DESTROY.containsKey(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_FEET;
|
||||
}
|
||||
|
||||
public double getBlockDecayTime(int level) {
|
||||
return this.blockDecayTime.getValue(level);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (player.isFlying() || !this.isAvailableToUse(player)) return;
|
||||
|
||||
Location from = event.getFrom();
|
||||
Location to = event.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 = EnchantUtils.getLevel(boots, this.getBackend());
|
||||
if (level <= 0) return;
|
||||
|
||||
Block bTo = to.getBlock().getRelative(BlockFace.DOWN);
|
||||
boolean hasLava = Stream.of(FACES).anyMatch(face -> bTo.getRelative(face).getType() == Material.LAVA);
|
||||
if (!hasLava) return;
|
||||
|
||||
plugin.getEnchantNMS().handleFlameWalker(player, player.getLocation(), level).forEach(block -> {
|
||||
addBlock(block, Rnd.getDouble(this.getBlockDecayTime(level)) + 1);
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onFlameWalkerBlock(BlockBreakEvent event) {
|
||||
if (isBlock(event.getBlock())) {
|
||||
event.setDropItems(false);
|
||||
event.setExpToDrop(0);
|
||||
event.getBlock().setType(Material.LAVA);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onBlockExplode(EntityExplodeEvent event) {
|
||||
this.processExplosion(event.blockList());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onBlockExplode2(BlockExplodeEvent event) {
|
||||
this.processExplosion(event.blockList());
|
||||
}
|
||||
|
||||
private void processExplosion(@NotNull List<Block> blocks) {
|
||||
blocks.removeIf(block -> {
|
||||
if (isBlock(block)) {
|
||||
block.setType(Material.AIR);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onMagmaDamage(EntityDamageEvent event) {
|
||||
if (event.getCause() != EntityDamageEvent.DamageCause.HOT_FLOOR) return;
|
||||
if (!(event.getEntity() instanceof LivingEntity livingEntity)) return;
|
||||
if (!this.isAvailableToUse(livingEntity)) return;
|
||||
|
||||
EntityEquipment equipment = livingEntity.getEquipment();
|
||||
if (equipment == null) return;
|
||||
|
||||
ItemStack boots = equipment.getBoots();
|
||||
if (boots == null || boots.getType().isAir()) return;
|
||||
|
||||
int level = EnchantUtils.getLevel(boots, this.getBackend());
|
||||
if (level <= 0) return;
|
||||
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
static class BlockTickTask extends AbstractTask<ExcellentEnchants> {
|
||||
|
||||
public BlockTickTask(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, 1, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action() {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
BLOCKS_TO_DESTROY.keySet().removeIf(block -> {
|
||||
if (block.isEmpty() || block.getType() != Material.MAGMA_BLOCK) return true;
|
||||
|
||||
Pair<Long, Integer> pair = BLOCKS_TO_DESTROY.get(block);
|
||||
long time = pair.getFirst();
|
||||
if (now >= time) {
|
||||
if (Version.isAtLeast(Version.V1_19_R3)) {
|
||||
block.getWorld().getPlayers().forEach(player -> {
|
||||
player.sendBlockDamage(block.getLocation(), 0F, pair.getSecond());
|
||||
});
|
||||
}
|
||||
|
||||
block.setType(Material.LAVA);
|
||||
UniParticle.blockCrack(Material.MAGMA_BLOCK).play(block.getLocation(), 0.5, 0.7, 0.5, 0.03, 30);
|
||||
return true;
|
||||
}
|
||||
else if (Version.isAtLeast(Version.V1_19_R3)) {
|
||||
long diff = TimeUnit.MILLISECONDS.toSeconds(time - now);
|
||||
|
||||
float progress = (float) (1D - Math.min(1D, diff / 5D));
|
||||
if (progress > 1F) progress = 1F;
|
||||
if (progress < 0F) progress = 0F;
|
||||
|
||||
float finalProgress = progress;
|
||||
block.getWorld().getPlayers().forEach(player -> {
|
||||
player.sendBlockDamage(block.getLocation(), finalProgress, pair.getSecond());
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class HardenedEnchant extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
|
||||
|
||||
public static final String ID = "hardened";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public HardenedEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to obtain " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) when damaged.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"30.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.DAMAGE_RESISTANCE, false,
|
||||
"3.0" + Placeholders.ENCHANTMENT_LEVEL,
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getProtectPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
return this.addEffect(victim, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class IceShieldEnchant extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
|
||||
|
||||
public static final String ID = "ice_shield";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public IceShieldEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to freeze and apply " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) on attacker.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "25.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.SLOW, false,
|
||||
"3.0 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getProtectPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Chanced getChanceImplementation() {
|
||||
return this.chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.addEffect(damager, level)) return false;
|
||||
|
||||
damager.setFreezeTicks(damager.getMaxFreezeTicks());
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.blockCrack(Material.ICE).play(damager.getEyeLocation(), 0.25, 0.1, 20);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class JumpingEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
|
||||
|
||||
public static final String ID = "bunny_hop";
|
||||
|
||||
private PotionImplementation potionImplementation;
|
||||
private PeriodImplementation periodImplementation;
|
||||
|
||||
public JumpingEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.1);
|
||||
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.JUMP, true);
|
||||
this.periodImplementation = PeriodImplementation.create(this, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PeriodImplementation getPeriodImplementation() {
|
||||
return periodImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_FEET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityResurrectEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class KamikadzeEnchant extends ExcellentEnchant implements Chanced, DeathEnchant, EventListener {
|
||||
|
||||
public static final String ID = "self_destruction";
|
||||
private static final String PLACEHOLDER_EXPLOSION_POWER = "%enchantment_explosion_power%";
|
||||
|
||||
private EnchantScaler explosionSize;
|
||||
private boolean applyOnResurrect;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
private Entity exploder;
|
||||
|
||||
public KamikadzeEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("%enchantment_trigger_chance%% chance to create an explosion on death.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"20.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 10");
|
||||
|
||||
this.applyOnResurrect = JOption.create("Settings.Apply_On_Resurrect", true,
|
||||
"Sets whether or not enchantment will trigger on resurrect (when a totem is used)."
|
||||
).read(cfg);
|
||||
|
||||
this.explosionSize = EnchantScaler.read(this, "Settings.Explosion.Size",
|
||||
"1.0" + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"A size of the explosion. The more size - the bigger the damage.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_EXPLOSION_POWER, level -> NumberUtil.format(this.getExplosionSize(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
public boolean isApplyOnResurrect() {
|
||||
return this.applyOnResurrect;
|
||||
}
|
||||
|
||||
public final double getExplosionSize(int level) {
|
||||
return this.explosionSize.getValue(level);
|
||||
}
|
||||
|
||||
public boolean createExplosion(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
float size = (float) this.getExplosionSize(level);
|
||||
this.exploder = entity;
|
||||
boolean exploded = entity.getWorld().createExplosion(entity.getLocation(), size, false, false, entity);
|
||||
this.exploder = null;
|
||||
return exploded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDeath(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, ItemStack item, int level) {
|
||||
return this.createExplosion(entity, item, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResurrect(@NotNull EntityResurrectEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return this.isApplyOnResurrect() && this.createExplosion(entity, item, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKill(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, @NotNull Player killer, ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onItemDamage(EntityDamageByEntityEvent event) {
|
||||
if (this.exploder == null || event.getDamager() != this.exploder) return;
|
||||
|
||||
if (event.getEntity() instanceof Item || event.getEntity() == this.exploder) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class NightVisionEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
|
||||
|
||||
public static final String ID = "night_vision";
|
||||
|
||||
private PotionImplementation potionImplementation;
|
||||
private PeriodImplementation periodImplementation;
|
||||
|
||||
public NightVisionEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.7);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.NIGHT_VISION, true);
|
||||
this.periodImplementation = PeriodImplementation.create(this, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PeriodImplementation getPeriodImplementation() {
|
||||
return periodImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_HEAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.EntityUtil;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
|
||||
|
||||
public class RegrowthEnchant extends ExcellentEnchant implements Chanced, PassiveEnchant {
|
||||
|
||||
public static final String ID = "regrowth";
|
||||
|
||||
private static final String PLACEHOLDER_HEAL_AMOUNT = "%enchantment_heal_amount%";
|
||||
private static final String PLACEHOLDER_HEAL_MIN_HEALTH = "%enchantment_heal_min_health%";
|
||||
private static final String PLACEHOLDER_HEAL_MAX_HEALTH = "%enchantment_heal_max_health%";
|
||||
|
||||
private EnchantScaler healMinHealth;
|
||||
private EnchantScaler healMaxHealth;
|
||||
private EnchantScaler healAmount;
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PeriodImplementation periodImplementation;
|
||||
|
||||
public RegrowthEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Restores " + PLACEHOLDER_HEAL_AMOUNT + " hearts every few seconds.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.7);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"20.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
|
||||
|
||||
this.periodImplementation = PeriodImplementation.create(this, "100");
|
||||
|
||||
this.healMinHealth = EnchantScaler.read(this, "Settings.Heal.Min_Health", "0.5",
|
||||
"Minimal entity health for the enchantment to have effect.");
|
||||
this.healMaxHealth = EnchantScaler.read(this, "Settings.Heal.Max_Health", "20.0",
|
||||
"Maximal entity health when the enchantment will not heal anymore.");
|
||||
this.healAmount = EnchantScaler.read(this, "Settings.Heal.Amount", "0.25",
|
||||
"Amount of hearts to be restored.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_HEAL_AMOUNT, level -> NumberUtil.format(this.getHealAmount(level)));
|
||||
this.addPlaceholder(PLACEHOLDER_HEAL_MIN_HEALTH, level -> NumberUtil.format(this.getHealMaxHealth(level)));
|
||||
this.addPlaceholder(PLACEHOLDER_HEAL_MAX_HEALTH, level -> NumberUtil.format(this.getHealMaxHealth(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PeriodImplementation getPeriodImplementation() {
|
||||
return periodImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_TORSO;
|
||||
}
|
||||
|
||||
public double getHealAmount(int level) {
|
||||
return this.healAmount.getValue(level);
|
||||
}
|
||||
|
||||
public double getHealMinHealth(int level) {
|
||||
return this.healMinHealth.getValue(level);
|
||||
}
|
||||
|
||||
public double getHealMaxHealth(int level) {
|
||||
return this.healMaxHealth.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
double healthMax = EntityUtil.getAttribute(entity, Attribute.GENERIC_MAX_HEALTH);
|
||||
double healthHas = entity.getHealth();
|
||||
if (healthHas < this.getHealMinHealth(level) || healthHas > this.getHealMaxHealth(level)) return false;
|
||||
if (healthHas >= healthMax) return false;
|
||||
|
||||
double amount = Math.min(healthMax, healthHas + this.getHealAmount(level));
|
||||
entity.setHealth(amount);
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.of(Particle.HEART).play(entity.getEyeLocation(), 0.25, 0.1, 5);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
|
||||
|
||||
public class SaturationEnchant extends ExcellentEnchant implements PassiveEnchant {
|
||||
|
||||
public static final String ID = "saturation";
|
||||
|
||||
private static final String PLACEHOLDER_SATURATION_AMOUNT = "%enchantment_saturation_amount%";
|
||||
private static final String PLACEHOLDER_SATURATION_MAX_FOOD_LEVEL = "%enchantment_saturation_max_food_level%";
|
||||
|
||||
private EnchantScaler saturationAmount;
|
||||
private EnchantScaler saturationMaxFoodLevel;
|
||||
|
||||
private PeriodImplementation periodImplementation;
|
||||
|
||||
public SaturationEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Restores " + PLACEHOLDER_SATURATION_AMOUNT + " food points every few seconds.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.periodImplementation = PeriodImplementation.create(this, "100");
|
||||
|
||||
this.saturationAmount = EnchantScaler.read(this, "Settings.Saturation.Amount", Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Amount of food points to restore.");
|
||||
this.saturationMaxFoodLevel = EnchantScaler.read(this, "Settings.Saturation.Max_Food_Level", "20",
|
||||
"Maximal player's food level for the enchantment to stop feeding them.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_SATURATION_AMOUNT, level -> NumberUtil.format(this.getSaturationAmount(level)));
|
||||
this.addPlaceholder(PLACEHOLDER_SATURATION_MAX_FOOD_LEVEL, level -> NumberUtil.format(this.getMaxFoodLevel(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PeriodImplementation getPeriodImplementation() {
|
||||
return periodImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_HEAD;
|
||||
}
|
||||
|
||||
public final int getSaturationAmount(int level) {
|
||||
return (int) this.saturationAmount.getValue(level);
|
||||
}
|
||||
|
||||
public final int getMaxFoodLevel(int level) {
|
||||
return (int) this.saturationMaxFoodLevel.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
if (!(entity instanceof Player player)) return false;
|
||||
if (player.getFoodLevel() >= this.getMaxFoodLevel(level)) return false;
|
||||
|
||||
int amount = this.getSaturationAmount(level);
|
||||
player.setFoodLevel(Math.min(20, player.getFoodLevel() + amount));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class SpeedyEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
|
||||
|
||||
public static final String ID = "sonic";
|
||||
|
||||
private PotionImplementation potionImplementation;
|
||||
private PeriodImplementation periodImplementation;
|
||||
|
||||
public SpeedyEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.SPEED, true);
|
||||
this.periodImplementation = PeriodImplementation.create(this, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PeriodImplementation getPeriodImplementation() {
|
||||
return periodImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_FEET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.armor;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class StoppingForceEnchant extends ExcellentEnchant implements Chanced, CombatEnchant {
|
||||
|
||||
public static final String ID = "stopping_force";
|
||||
|
||||
public static final String PLACEHOLDER_KNOCKBACK_RESISTANCE = "%knockback_resistance%";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private EnchantScaler knockbackModifier;
|
||||
|
||||
public StoppingForceEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to resist knockback in combat by " + PLACEHOLDER_KNOCKBACK_RESISTANCE + "%.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "100.0");
|
||||
this.knockbackModifier = EnchantScaler.read(this, "Settings.Knockback_Modifier",
|
||||
"0.7 - " + Placeholders.ENCHANTMENT_LEVEL + " / 5.0",
|
||||
"Sets the knockback multiplier when taking damage.", "Lower value = less knockback.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_KNOCKBACK_RESISTANCE, level -> NumberUtil.format(this.getKnockbackModifier(level) * 100));
|
||||
}
|
||||
|
||||
public double getKnockbackModifier(int level) {
|
||||
return this.knockbackModifier.getValue(level);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.ARMOR_LEGS;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getProtectPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Chanced getChanceImplementation() {
|
||||
return this.chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
this.plugin.runTask(task -> {
|
||||
victim.setVelocity(victim.getVelocity().multiply(this.getKnockbackModifier(level)));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.AbstractArrow;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class DarknessArrowsEnchant extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
|
||||
|
||||
public static final String ID = "darkness_arrows";
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public DarknessArrowsEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.1);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.ASH));
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"25.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5.0");
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.DARKNESS, false,
|
||||
"4.0 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
|
||||
return arrow.addCustomEffect(this.createEffect(level), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.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.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class EnchantBomber extends ExcellentEnchant implements Chanced, BowEnchant {
|
||||
|
||||
public static final String ID = "bomber";
|
||||
public static final String PLACEHOLDER_FUSE_TICKS = "%enchantment_fuse_ticks%";
|
||||
|
||||
private EnchantScaler fuseTicks;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public EnchantBomber(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch TNT that explodes in " + PLACEHOLDER_FUSE_TICKS + "s.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.7);
|
||||
this.getDefaults().setConflicts(
|
||||
EnchantEnderBow.ID, EnchantGhast.ID,
|
||||
EnchantExplosiveArrows.ID, EnchantPoisonedArrows.ID, EnchantConfusingArrows.ID,
|
||||
EnchantWitheredArrows.ID, EnchantElectrifiedArrows.ID, EnchantDragonfireArrows.ID,
|
||||
DarknessArrowsEnchant.ID,
|
||||
EnchantHover.ID, FlareEnchant.ID,
|
||||
Enchantment.ARROW_FIRE.getKey().getKey(),
|
||||
Enchantment.ARROW_KNOCKBACK.getKey().getKey(),
|
||||
Enchantment.ARROW_DAMAGE.getKey().getKey()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"5.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
this.fuseTicks = EnchantScaler.read(this, "Settings.Fuse_Ticks",
|
||||
"100 - " + Placeholders.ENCHANTMENT_LEVEL + " * 10",
|
||||
"Sets fuse ticks (before it will explode) for the launched TNT.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_FUSE_TICKS, level -> NumberUtil.format((double) this.getFuseTicks(level) / 20D));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
public int getFuseTicks(int level) {
|
||||
return (int) this.fuseTicks.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getShootPriority() {
|
||||
return EventPriority.LOWEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!(event.getProjectile() instanceof Projectile projectile)) return false;
|
||||
|
||||
TNTPrimed primed = projectile.getWorld().spawn(projectile.getLocation(), TNTPrimed.class);
|
||||
primed.setVelocity(projectile.getVelocity().multiply(event.getForce() * 1.25));
|
||||
primed.setFuseTicks(this.getFuseTicks(level));
|
||||
primed.setSource(shooter);
|
||||
event.setProjectile(primed);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.AbstractArrow;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class EnchantConfusingArrows extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
|
||||
|
||||
public static final String ID = "confusing_arrows";
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public EnchantConfusingArrows(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.1);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.SPELL_MOB));
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"20.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5.0");
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.CONFUSION, false,
|
||||
"6.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 3.0",
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
|
||||
return arrow.addCustomEffect(this.createEffect(level), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.AreaEffectCloud;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.ThrownPotion;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.LingeringPotionSplashEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.projectiles.ProjectileSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class EnchantDragonfireArrows extends ExcellentEnchant implements Chanced, Arrowed, BowEnchant {
|
||||
|
||||
public static final String ID = "dragonfire_arrows";
|
||||
|
||||
public static final String PLACEHOLDER_FIRE_RADIUS = "%enchantment_fire_radius%";
|
||||
public static final String PLACEHOLDER_FIRE_DURATION = "%enchantment_fire_duration%";
|
||||
|
||||
private EnchantScaler fireDuration;
|
||||
private EnchantScaler fireRadius;
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public EnchantDragonfireArrows(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an dragonfire arrow (R=" + PLACEHOLDER_FIRE_RADIUS + ", " + PLACEHOLDER_FIRE_DURATION + "s).");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.7);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.DRAGON_BREATH));
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
|
||||
this.fireDuration = EnchantScaler.read(this, "Settings.Fire.Duration",
|
||||
"100 * " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Sets the dragonfire cloud effect duration (in ticks). 20 ticks = 1 second.");
|
||||
this.fireRadius = EnchantScaler.read(this, "Settings.Fire.Radius",
|
||||
"2.0 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Sets the dragonfire cloud effect radius.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_FIRE_DURATION, level -> NumberUtil.format(this.getFireDuration(level) / 20D));
|
||||
this.addPlaceholder(PLACEHOLDER_FIRE_RADIUS, level -> NumberUtil.format(this.getFireRadius(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
public int getFireDuration(int level) {
|
||||
return (int) this.fireDuration.getValue(level);
|
||||
}
|
||||
|
||||
public double getFireRadius(int level) {
|
||||
return this.fireRadius.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
return this.checkTriggerChance(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
if (!this.isOurProjectile(projectile)) return false;
|
||||
if (event.getHitEntity() != null) return false;
|
||||
if (projectile.getShooter() == null) return false;
|
||||
|
||||
this.createCloud(projectile.getShooter(), projectile.getLocation() , level);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.isOurProjectile(projectile)) return false;
|
||||
|
||||
this.createCloud(shooter, victim.getLocation(), level);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void createCloud(@NotNull ProjectileSource shooter, @NotNull Location location, int level) {
|
||||
World world = location.getWorld();
|
||||
if (world == null) return;
|
||||
|
||||
// There are some tweaks to respect protection plugins using even call.
|
||||
|
||||
ItemStack item = new ItemStack(Material.LINGERING_POTION);
|
||||
ItemUtil.mapMeta(item, meta -> {
|
||||
if (meta instanceof PotionMeta potionMeta) {
|
||||
potionMeta.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 20, 0), true);
|
||||
}
|
||||
});
|
||||
|
||||
ThrownPotion potion = shooter.launchProjectile(ThrownPotion.class);
|
||||
potion.setItem(item);
|
||||
potion.teleport(location);
|
||||
|
||||
AreaEffectCloud cloud = world.spawn(location, AreaEffectCloud.class);
|
||||
cloud.clearCustomEffects();
|
||||
cloud.setSource(shooter);
|
||||
cloud.setParticle(Particle.DRAGON_BREATH);
|
||||
cloud.setRadius((float) this.getFireRadius(level));
|
||||
cloud.setDuration(this.getFireDuration(level));
|
||||
cloud.setRadiusPerTick((7.0F - cloud.getRadius()) / (float) cloud.getDuration());
|
||||
cloud.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 1, 1), true);
|
||||
|
||||
LingeringPotionSplashEvent splashEvent = new LingeringPotionSplashEvent(potion, cloud);
|
||||
plugin.getPluginManager().callEvent(splashEvent);
|
||||
if (splashEvent.isCancelled()) {
|
||||
cloud.remove();
|
||||
}
|
||||
potion.remove();
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.LocationUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class EnchantElectrifiedArrows extends ExcellentEnchant implements Chanced, Arrowed, BowEnchant {
|
||||
|
||||
public static final String ID = "electrified_arrows";
|
||||
|
||||
private static final String META_NO_ITEM_DAMAGE = "itemNoDamage";
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public EnchantElectrifiedArrows(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an electrified arrow.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.3);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.FIREWORKS_SPARK));
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
return this.checkTriggerChance(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
if (!this.isOurProjectile(projectile)) return false;
|
||||
if (event.getHitEntity() != null || event.getHitBlock() == null) return false;
|
||||
|
||||
Block block = event.getHitBlock();
|
||||
block.getWorld().strikeLightning(block.getLocation()).setMetadata(META_NO_ITEM_DAMAGE, new FixedMetadataValue(plugin, true));
|
||||
if (this.hasVisualEffects()) {
|
||||
Location center = LocationUtil.getCenter(block.getLocation());
|
||||
UniParticle.blockCrack(block.getType()).play(center, 1, 0.05, 120);
|
||||
UniParticle.of(Particle.FIREWORKS_SPARK).play(center, 1, 0.05, 120);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.isOurProjectile(projectile)) return false;
|
||||
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
if (victim.isDead()) return;
|
||||
victim.setNoDamageTicks(0);
|
||||
victim.getWorld().strikeLightning(victim.getLocation()).setMetadata(META_NO_ITEM_DAMAGE, new FixedMetadataValue(plugin, true));
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onItemDamage(EntityDamageByEntityEvent e) {
|
||||
if (!e.getDamager().hasMetadata(META_NO_ITEM_DAMAGE)) return;
|
||||
if (e.getEntity() instanceof Item || e.getEntity() instanceof ItemFrame) {
|
||||
e.setCancelled(true);
|
||||
e.getEntity().setFireTicks(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.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.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class EnchantEnderBow extends ExcellentEnchant implements BowEnchant, Chanced {
|
||||
|
||||
public static final String ID = "ender_bow";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public EnchantEnderBow(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Shoots ender pearls instead of arrows.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(1.0);
|
||||
|
||||
this.getDefaults().setConflicts(
|
||||
EnchantBomber.ID, EnchantGhast.ID,
|
||||
EnchantExplosiveArrows.ID, EnchantPoisonedArrows.ID, EnchantConfusingArrows.ID,
|
||||
EnchantWitheredArrows.ID, EnchantElectrifiedArrows.ID, EnchantDragonfireArrows.ID,
|
||||
DarknessArrowsEnchant.ID, VampiricArrowsEnchant.ID,
|
||||
EnchantHover.ID, FlareEnchant.ID,
|
||||
Enchantment.ARROW_FIRE.getKey().getKey(),
|
||||
Enchantment.ARROW_KNOCKBACK.getKey().getKey(),
|
||||
Enchantment.ARROW_DAMAGE.getKey().getKey()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getShootPriority() {
|
||||
return EventPriority.LOWEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!(event.getProjectile() instanceof Projectile projectile)) return false;
|
||||
|
||||
EnderPearl pearl = shooter.launchProjectile(EnderPearl.class);
|
||||
pearl.setVelocity(projectile.getVelocity());
|
||||
event.setProjectile(pearl);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class EnchantExplosiveArrows extends ExcellentEnchant implements Chanced, Arrowed, BowEnchant {
|
||||
|
||||
public static final String ID = "explosive_arrows";
|
||||
public static final String PLACEHOLDER_EXPLOSION_POWER = "%enchantment_explosion_power%";
|
||||
|
||||
private boolean explosionFireSpread;
|
||||
private boolean explosionDamageItems;
|
||||
private boolean explosionDamageBlocks;
|
||||
private EnchantScaler explosionSize;
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
private Entity lastExploder;
|
||||
|
||||
public EnchantExplosiveArrows(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an explosive arrow.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.7);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.SMOKE_NORMAL));
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
|
||||
this.explosionFireSpread = JOption.create("Settings.Explosion.Fire_Spread", true,
|
||||
"When 'true' creates fire on nearby blocks.").read(cfg);
|
||||
this.explosionDamageItems = JOption.create("Settings.Explosion.Damage_Items", false,
|
||||
"When 'true' inflicts damage to items on the ground.").read(cfg);
|
||||
this.explosionDamageBlocks = JOption.create("Settings.Explosion.Damage_Blocks", false,
|
||||
"When 'true' allows to break blocks by explosion.").read(cfg);
|
||||
this.explosionSize = EnchantScaler.read(this, "Settings.Explosion.Size",
|
||||
"2.0 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Sets the explosion size. The more size - the bigger explosion.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_EXPLOSION_POWER, level -> NumberUtil.format(this.getExplosionSize(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
public final double getExplosionSize(int level) {
|
||||
return this.explosionSize.getValue(level);
|
||||
}
|
||||
|
||||
public final boolean isExplosionFireSpread() {
|
||||
return this.explosionFireSpread;
|
||||
}
|
||||
|
||||
public final boolean isExplosionDamageBlocks() {
|
||||
return this.explosionDamageBlocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
return this.checkTriggerChance(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
if (!this.isOurProjectile(projectile)) return false;
|
||||
|
||||
if (projectile.getShooter() instanceof Entity entity) {
|
||||
this.lastExploder = entity;
|
||||
}
|
||||
|
||||
World world = projectile.getWorld();
|
||||
float explSize = (float) this.getExplosionSize(level);
|
||||
boolean explFire = this.isExplosionFireSpread();
|
||||
boolean explBlocks = this.isExplosionDamageBlocks();
|
||||
boolean exploded = world.createExplosion(projectile.getLocation(), explSize, explFire, explBlocks, this.lastExploder);
|
||||
this.lastExploder = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onItemDamage(EntityDamageByEntityEvent event) {
|
||||
if (event.getCause() != EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) return;
|
||||
if (this.explosionDamageItems) return;
|
||||
if (this.lastExploder == null || this.lastExploder != event.getDamager()) return;
|
||||
|
||||
if (event.getEntity() instanceof Item || event.getEntity() instanceof ItemFrame) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.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.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
public class EnchantGhast extends ExcellentEnchant implements BowEnchant, Chanced {
|
||||
|
||||
public static final String ID = "ghast";
|
||||
|
||||
private boolean fireSpread;
|
||||
private EnchantScaler yield;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public EnchantGhast(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Shoots fireballs instead of arrows.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.3);
|
||||
|
||||
this.getDefaults().setConflicts(
|
||||
EnchantEnderBow.ID, EnchantBomber.ID,
|
||||
EnchantExplosiveArrows.ID, EnchantPoisonedArrows.ID, EnchantConfusingArrows.ID,
|
||||
EnchantWitheredArrows.ID, EnchantElectrifiedArrows.ID, EnchantDragonfireArrows.ID,
|
||||
DarknessArrowsEnchant.ID, VampiricArrowsEnchant.ID,
|
||||
EnchantHover.ID, FlareEnchant.ID,
|
||||
Enchantment.ARROW_FIRE.getKey().getKey(),
|
||||
Enchantment.ARROW_KNOCKBACK.getKey().getKey(),
|
||||
Enchantment.ARROW_DAMAGE.getKey().getKey()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "100");
|
||||
this.fireSpread = JOption.create("Settings.Fire_Spread", true,
|
||||
"When 'true' creates fire on nearby blocks.").read(cfg);
|
||||
this.yield = EnchantScaler.read(this, "Settings.Yield", "1.0 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Fireball explosion size/radius. The more value = the bigger the explosion.");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
public boolean isFireSpread() {
|
||||
return fireSpread;
|
||||
}
|
||||
|
||||
public float getYield(int level) {
|
||||
return (float) this.yield.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getShootPriority() {
|
||||
return EventPriority.LOWEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!(event.getProjectile() instanceof Projectile projectile)) 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 (EnchantUtils.contains(bow, 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));
|
||||
|
||||
event.setProjectile(fireball);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile,
|
||||
@NotNull LivingEntity shooter, @NotNull LivingEntity victim,
|
||||
@NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.AbstractArrow;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class EnchantHover extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
|
||||
|
||||
public static final String ID = "hover";
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public EnchantHover(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.1);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.BUBBLE_POP));
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.LEVITATION, false,
|
||||
"2.5 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
|
||||
return arrow.addCustomEffect(this.createEffect(level), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.AbstractArrow;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class EnchantPoisonedArrows extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
|
||||
|
||||
public static final String ID = "poisoned_arrows";
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public EnchantPoisonedArrows(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.1);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.SLIME));
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"25.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5");
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.POISON, false,
|
||||
"2.5 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
|
||||
return arrow.addCustomEffect(this.createEffect(level), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.AbstractArrow;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class EnchantWitheredArrows extends ExcellentEnchant implements Chanced, Arrowed, Potioned, BowEnchant {
|
||||
|
||||
public static final String ID = "withered_arrows";
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public EnchantWitheredArrows(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to launch an arrow with " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.)");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.5);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.SPELL_WITCH));
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"15.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5.0");
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.WITHER, false,
|
||||
"2.5 + " + Placeholders.ENCHANTMENT_LEVEL + " * 0.75",
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
|
||||
return arrow.addCustomEffect(this.createEffect(level), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.Directional;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class FlareEnchant extends ExcellentEnchant implements Chanced, Arrowed, BowEnchant {
|
||||
|
||||
public static final String ID = "flare";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private ArrowImplementation arrowImplementation;
|
||||
|
||||
public FlareEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to create a torch where arrow lands.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "100.0");
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.of(Particle.FIREWORKS_SPARK));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getHitPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Chanced getChanceImplementation() {
|
||||
return this.chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrowImplementation getArrowImplementation() {
|
||||
return this.arrowImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
this.addData(arrow);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent e, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
Block block = e.getHitBlock();
|
||||
if (block == null) return false;
|
||||
|
||||
BlockFace face = e.getHitBlockFace();
|
||||
if (face == null || face == BlockFace.DOWN) return false;
|
||||
|
||||
Block relative = block.getRelative(face);
|
||||
if (!relative.getType().isAir()) return false;
|
||||
|
||||
if (projectile.getShooter() instanceof Player player) {
|
||||
BlockPlaceEvent event = new BlockPlaceEvent(relative, relative.getState(), block, new ItemStack(Material.TORCH), player,true, EquipmentSlot.HAND);
|
||||
plugin.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled() || !event.canBuild()) return false;
|
||||
}
|
||||
|
||||
if (face == BlockFace.UP) {
|
||||
relative.setType(Material.TORCH);
|
||||
}
|
||||
else {
|
||||
relative.setType(Material.WALL_TORCH);
|
||||
|
||||
Directional directional = (Directional) relative.getBlockData();
|
||||
directional.setFacing(face);
|
||||
relative.setBlockData(directional, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class SniperEnchant extends ExcellentEnchant implements BowEnchant, Chanced {
|
||||
|
||||
public static final String ID = "sniper";
|
||||
|
||||
private static final String PLACEHOLDER_PROJECTILE_SPEED = "%enchantment_projectile_speed%";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private EnchantScaler speedModifier;
|
||||
|
||||
public SniperEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
|
||||
this.getDefaults().setDescription("Increases projectile speed by " + PLACEHOLDER_PROJECTILE_SPEED + "%");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "100.0");
|
||||
this.speedModifier = EnchantScaler.read(this, "Settings.Speed_Modifier",
|
||||
"1.0 + " + Placeholders.ENCHANTMENT_LEVEL + " / 5.0", "Sets projectile's speed modifier.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_PROJECTILE_SPEED, level -> NumberUtil.format(this.getSpeedModifier(level) * 100D));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Chanced getChanceImplementation() {
|
||||
return this.chanceImplementation;
|
||||
}
|
||||
|
||||
public double getSpeedModifier(int level) {
|
||||
return this.speedModifier.getValue(level);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getShootPriority() {
|
||||
return EventPriority.LOWEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
double modifier = this.getSpeedModifier(level);
|
||||
|
||||
Entity entity = event.getProjectile();
|
||||
Vector vector = entity.getVelocity();
|
||||
entity.setVelocity(vector.multiply(modifier));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.bow;
|
||||
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityRegainHealthEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.EntityUtil;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BowEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ArrowImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class VampiricArrowsEnchant extends ExcellentEnchant implements BowEnchant, Arrowed, Chanced {
|
||||
|
||||
public static final String ID = "vampiric_arrows";
|
||||
|
||||
public static final String PLACEHOLDER_HEAL_AMOUNT = "%heal_amount%";
|
||||
|
||||
private ArrowImplementation arrowImplementation;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private EnchantScaler healAmount;
|
||||
|
||||
public VampiricArrowsEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to restore " + PLACEHOLDER_HEAL_AMOUNT + "❤ on arrow hit.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.3);
|
||||
this.getDefaults().setConflicts(EnchantEnderBow.ID, EnchantGhast.ID, EnchantBomber.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.arrowImplementation = ArrowImplementation.create(this, UniParticle.redstone(Color.RED, 1f));
|
||||
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "20.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
|
||||
this.healAmount = EnchantScaler.read(this, "Settings.Heal_Amount",
|
||||
Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Amount of health to be restored on hit.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_HEAL_AMOUNT, level -> NumberUtil.format(this.getHealAmount(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BOW;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Arrowed getArrowImplementation() {
|
||||
return this.arrowImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Chanced getChanceImplementation() {
|
||||
return this.chanceImplementation;
|
||||
}
|
||||
|
||||
public double getHealAmount(int level) {
|
||||
return this.healAmount.getValue(level);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getDamagePriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShoot(@NotNull EntityShootBowEvent event, @NotNull LivingEntity shooter, @NotNull ItemStack bow, int level) {
|
||||
if (!(event.getProjectile() instanceof Arrow arrow)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
this.addData(arrow);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHit(@NotNull ProjectileHitEvent event, LivingEntity user, @NotNull Projectile projectile, @NotNull ItemStack bow, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDamage(@NotNull EntityDamageByEntityEvent event, @NotNull Projectile projectile, @NotNull LivingEntity shooter, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (shooter.isDead() || shooter.getHealth() <= 0D) return false;
|
||||
|
||||
double healAmount = this.getHealAmount(level);
|
||||
if (healAmount <= 0D) return false;
|
||||
|
||||
double health = shooter.getHealth();
|
||||
double maxHealth = EntityUtil.getAttribute(shooter, Attribute.GENERIC_MAX_HEALTH);
|
||||
if (health >= maxHealth) return false;
|
||||
|
||||
EntityRegainHealthEvent healthEvent = new EntityRegainHealthEvent(shooter, healAmount, EntityRegainHealthEvent.RegainReason.CUSTOM);
|
||||
plugin.getPluginManager().callEvent(healthEvent);
|
||||
if (healthEvent.isCancelled()) return false;
|
||||
|
||||
shooter.setHealth(Math.min(maxHealth, health + healAmount));
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.of(Particle.HEART).play(shooter.getEyeLocation(), 0.25f, 0.15f, 5);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.fishing;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.FishingEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
|
||||
public class AutoReelEnchant extends ExcellentEnchant implements FishingEnchant {
|
||||
|
||||
public static final String ID = "auto_reel";
|
||||
|
||||
public AutoReelEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Automatically reels in a hook on bite.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(1.0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.FISHING_ROD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFishing(@NotNull PlayerFishEvent event, @NotNull ItemStack item, int level) {
|
||||
if (event.getState() != PlayerFishEvent.State.BITE) return false;
|
||||
|
||||
this.plugin.runTask(task -> {
|
||||
if (event.isCancelled()) return;
|
||||
|
||||
plugin.getEnchantNMS().sendAttackPacket(event.getPlayer(), 0);
|
||||
plugin.getEnchantNMS().retrieveHook(event.getHook(), item);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.fishing;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Drowned;
|
||||
import org.bukkit.entity.FishHook;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nexmedia.engine.utils.values.UniSound;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.FishingEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class CurseOfDrownedEnchant extends ExcellentEnchant implements FishingEnchant, Chanced {
|
||||
|
||||
public static final String ID = "curse_of_drowned";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public CurseOfDrownedEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to fish up a Drowned Zombie.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"5.0 + " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.FISHING_ROD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFishing(@NotNull PlayerFishEvent event, @NotNull ItemStack item, int level) {
|
||||
if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
FishHook hook = event.getHook();
|
||||
Drowned drowned = hook.getWorld().spawn(hook.getLocation(), Drowned.class);
|
||||
hook.setHookedEntity(drowned);
|
||||
hook.pullHookedEntity();
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.of(Particle.WATER_SPLASH).play(hook.getLocation(), 0.5, 0.1, 50);
|
||||
UniSound.of(Sound.ENTITY_DROWNED_AMBIENT).play(event.getPlayer());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.fishing;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.FishingEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class DoubleCatchEnchant extends ExcellentEnchant implements FishingEnchant, Chanced {
|
||||
|
||||
public static final String ID = "double_catch";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public DoubleCatchEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Increases amount of caught item by x2 with " + Placeholders.ENCHANTMENT_CHANCE + "% chance.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"10.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.FISHING_ROD;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getFishingPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return this.chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFishing(@NotNull PlayerFishEvent event, @NotNull ItemStack item, int level) {
|
||||
if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) return false;
|
||||
if (!(event.getCaught() instanceof Item drop)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
ItemStack stack = drop.getItemStack();
|
||||
stack.setAmount(Math.min(stack.getMaxStackSize(), stack.getAmount() * 2));
|
||||
drop.setItemStack(stack);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.fishing;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.FishHook;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
public class RiverMasterEnchant extends ExcellentEnchant implements GenericEnchant, EventListener {
|
||||
|
||||
public static final String ID = "river_master";
|
||||
|
||||
private EnchantScaler distanceMod;
|
||||
|
||||
public RiverMasterEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Increases casting distance.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.distanceMod = EnchantScaler.read(this, "Settings.Distance_Modifier",
|
||||
"1.25 + " + Placeholders.ENCHANTMENT_LEVEL + " / 5",
|
||||
"Multiplies the casted fish hook's velocity by specified value.",
|
||||
"Setting too high values will result in hook auto removal by vanilla game/server mechanics.");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.FISHING_ROD;
|
||||
}
|
||||
|
||||
public double getDistanceMod(int level) {
|
||||
return this.distanceMod.getValue(level);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onHookLaunch(ProjectileLaunchEvent event) {
|
||||
if (!(event.getEntity() instanceof FishHook hook)) return;
|
||||
if (!(hook.getShooter() instanceof Player player)) return;
|
||||
|
||||
ItemStack rod = EnchantUtils.getFishingRod(player);
|
||||
if (rod == null) return;
|
||||
|
||||
int level = EnchantUtils.getLevel(rod, this.getBackend());
|
||||
if (level < 1) return;
|
||||
|
||||
if (this.isOutOfCharges(rod)) return;
|
||||
|
||||
hook.setVelocity(hook.getVelocity().multiply(this.getDistanceMod(level)));
|
||||
|
||||
this.consumeCharges(rod, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.fishing;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.FishingEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
|
||||
public class SeasonedAnglerEnchant extends ExcellentEnchant implements FishingEnchant {
|
||||
|
||||
public static final String ID = "seasoned_angler";
|
||||
|
||||
private EnchantScaler expMod;
|
||||
|
||||
public SeasonedAnglerEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Increases amount of XP gained from fishing by " + Placeholders.GENERIC_AMOUNT + "%.");
|
||||
this.getDefaults().setLevelMax(4);
|
||||
this.getDefaults().setTier(0.1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.expMod = EnchantScaler.read(this, "Settings.Exp_Percent",
|
||||
"25.0 * " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Amount (in percent) of additional XP from fishing.");
|
||||
|
||||
this.addPlaceholder(Placeholders.GENERIC_AMOUNT, level -> NumberUtil.format(this.getExpPercent(level)));
|
||||
}
|
||||
|
||||
public int getExpPercent(int level) {
|
||||
return (int) this.expMod.getValue(level);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.FISHING_ROD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFishing(@NotNull PlayerFishEvent event, @NotNull ItemStack item, int level) {
|
||||
if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) return false;
|
||||
if (event.getExpToDrop() == 0) return false;
|
||||
|
||||
int expDrop = event.getExpToDrop();
|
||||
int expPercent = this.getExpPercent(level);
|
||||
int expModified = (int) Math.ceil(expDrop * (1D + expPercent / 100D));
|
||||
|
||||
event.setExpToDrop(expModified);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.fishing;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.inventory.CookingRecipe;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.FishingEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class SurvivalistEnchant extends ExcellentEnchant implements FishingEnchant, Chanced {
|
||||
|
||||
public static final String ID = "survivalist";
|
||||
|
||||
private final Set<CookingRecipe<?>> cookingRecipes;
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public SurvivalistEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Automatically cooks fish if what is caught is raw.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.4);
|
||||
|
||||
this.cookingRecipes = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "100");
|
||||
|
||||
this.cookingRecipes.clear();
|
||||
this.plugin.getServer().recipeIterator().forEachRemaining(recipe -> {
|
||||
if (recipe instanceof CookingRecipe<?> cookingRecipe) {
|
||||
this.cookingRecipes.add(cookingRecipe);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.FISHING_ROD;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getFishingPriority() {
|
||||
return EventPriority.HIGH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFishing(@NotNull PlayerFishEvent event, @NotNull ItemStack item, int level) {
|
||||
if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!(event.getCaught() instanceof Item drop)) return false;
|
||||
|
||||
ItemStack stack = drop.getItemStack();
|
||||
|
||||
CookingRecipe<?> recipe = this.cookingRecipes.stream().filter(r -> r.getInput().isSimilar(stack)).findFirst().orElse(null);
|
||||
if (recipe == null) return false;
|
||||
|
||||
ItemStack cooked = recipe.getResult();
|
||||
cooked.setAmount(stack.getAmount());
|
||||
drop.setItemStack(cooked);
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.meta;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.api.config.JYML;
|
||||
import su.nexmedia.engine.utils.PDCUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchantsAPI;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.task.ArrowTrailsTask;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public final class ArrowImplementation implements Arrowed {
|
||||
|
||||
private final ExcellentEnchant enchant;
|
||||
private final NamespacedKey projectileKey;
|
||||
|
||||
private final UniParticle trailParticle;
|
||||
|
||||
private ArrowImplementation(@NotNull ExcellentEnchant enchant, @Nullable UniParticle trailParticle) {
|
||||
this.enchant = enchant;
|
||||
this.projectileKey = new NamespacedKey(ExcellentEnchantsAPI.PLUGIN, "arrow.enchant_id");
|
||||
this.trailParticle = trailParticle;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ArrowImplementation create(@NotNull ExcellentEnchant enchant) {
|
||||
return create(enchant, UniParticle.of(Particle.REDSTONE));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ArrowImplementation create(@NotNull ExcellentEnchant enchant, @NotNull UniParticle particle) {
|
||||
JYML cfg = enchant.getConfig();
|
||||
|
||||
UniParticle effect = new JOption<>("Settings.Arrow.Trail_Effect",
|
||||
(cfg1, path, def) -> UniParticle.read(cfg1, path),
|
||||
particle,
|
||||
"Sets particle effect for the arrow trail of this enchantment."
|
||||
).setWriter((cfg1, path, particle1) -> particle1.write(cfg1, path)).read(cfg);
|
||||
|
||||
return new ArrowImplementation(enchant, effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Arrowed getArrowImplementation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTrail(@NotNull Projectile projectile) {
|
||||
if (!this.enchant.hasVisualEffects()) return;
|
||||
if (this.getTrailParticle().isEmpty()) return;
|
||||
|
||||
this.getTrailParticle().ifPresent(particle -> {
|
||||
ArrowTrailsTask.add(projectile, particle);
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Optional<UniParticle> getTrailParticle() {
|
||||
return trailParticle == null ? Optional.empty() : Optional.of(trailParticle);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamespacedKey getProjectileKey() {
|
||||
return projectileKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addData(@NotNull Projectile projectile) {
|
||||
PDCUtil.set(projectile, this.getProjectileKey(), this.enchant.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOurProjectile(@NotNull Projectile projectile) {
|
||||
String enchantId = PDCUtil.getString(projectile, this.getProjectileKey()).orElse(null);
|
||||
return this.enchant.getId().equalsIgnoreCase(enchantId);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.meta;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
|
||||
public final class ChanceImplementation implements Chanced {
|
||||
|
||||
//private final ExcellentEnchant enchant;
|
||||
private final EnchantScaler triggerChance;
|
||||
|
||||
private ChanceImplementation(@NotNull ExcellentEnchant enchant, @NotNull EnchantScaler triggerChance) {
|
||||
//this.enchant = enchant;
|
||||
this.triggerChance = triggerChance;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ChanceImplementation create(@NotNull ExcellentEnchant enchant) {
|
||||
return create(enchant, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ChanceImplementation create(@NotNull ExcellentEnchant enchant, @NotNull String def) {
|
||||
return new ChanceImplementation(enchant, EnchantScaler.read(enchant, "Settings.Trigger_Chance", def,
|
||||
"A chance that this enchantment will be triggered."));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Chanced getChanceImplementation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTriggerChance(int level) {
|
||||
return this.triggerChance.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTriggerChance(int level) {
|
||||
return Rnd.chance(this.getTriggerChance(level));
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.meta;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Periodic;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
|
||||
public class PeriodImplementation implements Periodic {
|
||||
|
||||
private final EnchantScaler triggerInterval;
|
||||
|
||||
private long nextTriggerTime;
|
||||
|
||||
public PeriodImplementation(@NotNull ExcellentEnchant enchant, @NotNull EnchantScaler triggerInterval) {
|
||||
this.triggerInterval = triggerInterval;
|
||||
this.updateTriggerTime();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PeriodImplementation create(@NotNull ExcellentEnchant enchant) {
|
||||
return create(enchant, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PeriodImplementation create(@NotNull ExcellentEnchant enchant, @NotNull String def) {
|
||||
return new PeriodImplementation(enchant, EnchantScaler.read(enchant, "Settings.Trigger_Interval", def,
|
||||
"Sets how often (in ticks) this enchantment will be triggered.",
|
||||
"20 ticks = 1 second."));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Periodic getPeriodImplementation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getInterval() {
|
||||
return (long) this.triggerInterval.getValue(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextTriggerTime() {
|
||||
return nextTriggerTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTriggerTime() {
|
||||
return System.currentTimeMillis() >= this.getNextTriggerTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTriggerTime() {
|
||||
this.nextTriggerTime = System.currentTimeMillis() + this.getInterval() * 50L - 100L;
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.meta;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.config.Config;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
|
||||
public final class PotionImplementation implements Potioned {
|
||||
|
||||
private final ExcellentEnchant enchant;
|
||||
private final PotionEffectType effectType;
|
||||
private final EnchantScaler duration;
|
||||
private final EnchantScaler amplifier;
|
||||
private final boolean isPermanent;
|
||||
|
||||
private PotionImplementation(@NotNull ExcellentEnchant enchant,
|
||||
@NotNull PotionEffectType effectType, boolean isPermanent,
|
||||
@NotNull EnchantScaler duration, @NotNull EnchantScaler amplifier) {
|
||||
this.enchant = enchant;
|
||||
this.effectType = effectType;
|
||||
this.duration = duration;
|
||||
this.amplifier = amplifier;
|
||||
this.isPermanent = isPermanent;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Potioned getPotionImplementation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public static PotionImplementation create(@NotNull ExcellentEnchant enchant, @NotNull PotionEffectType type, boolean isPermanent) {
|
||||
return create(enchant, type, isPermanent, "5 * " + Placeholders.ENCHANTMENT_LEVEL, Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
public static PotionImplementation create(@NotNull ExcellentEnchant enchant,
|
||||
@NotNull PotionEffectType type, boolean isPermanent,
|
||||
@NotNull String duration, @NotNull String amplifier) {
|
||||
|
||||
EnchantScaler durationScale = EnchantScaler.read(enchant, "Settings.Potion_Effect.Duration", duration,
|
||||
"Potion effect duration (in seconds). This setting is useless for 'permanent' effects.");
|
||||
|
||||
EnchantScaler amplifierScale = EnchantScaler.read(enchant, "Settings.Potion_Effect.Level", amplifier,
|
||||
"Potion effect level.");
|
||||
|
||||
return new PotionImplementation(enchant, type, isPermanent, durationScale, amplifierScale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermanent() {
|
||||
return this.isPermanent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PotionEffectType getEffectType() {
|
||||
return this.effectType;
|
||||
}
|
||||
|
||||
public int getEffectDuration(int level) {
|
||||
if (this.isPermanent()) {
|
||||
int duration = Config.TASKS_PASSIVE_ENCHANTS_TRIGGER_INTERVAL.get().intValue() * 2;
|
||||
if (this.getEffectType().getName().equalsIgnoreCase(PotionEffectType.NIGHT_VISION.getName()) && duration < 600) {
|
||||
duration += 30 * 20;
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
return (int) (this.duration.getValue(level) * 20);
|
||||
}
|
||||
|
||||
public int getEffectAmplifier(int level) {
|
||||
return (int) this.amplifier.getValue(level);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PotionEffect createEffect(int level) {
|
||||
int duration = this.getEffectDuration(level);
|
||||
int amplifier = Math.max(0, this.getEffectAmplifier(level) - 1);
|
||||
|
||||
return new PotionEffect(this.getEffectType(), duration, amplifier, false, this.enchant.hasVisualEffects());
|
||||
}
|
||||
|
||||
public boolean addEffect(@NotNull LivingEntity target, int level) {
|
||||
target.addPotionEffect(this.createEffect(level));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
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.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.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
import su.nightexpress.excellentenchants.hook.impl.NoCheatPlusHook;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BlastMiningEnchant extends ExcellentEnchant implements Chanced, BlockBreakEnchant, EventListener {
|
||||
|
||||
public static final String ID = "blast_mining";
|
||||
public static final String PLACEHOLDER_EXPLOSION_POWER = "%enchantment_explosion_power%";
|
||||
|
||||
private EnchantScaler explosionPower;
|
||||
private EnchantScaler minBlockStrength;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
private int explodeLevel;
|
||||
|
||||
public BlastMiningEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to mine blocks by explosion.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(1.0);
|
||||
this.getDefaults().setConflicts(VeinminerEnchant.ID, TunnelEnchant.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"20.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
|
||||
this.explosionPower = EnchantScaler.read(this, "Settings.Explosion.Power",
|
||||
"3.0 + (" + Placeholders.ENCHANTMENT_LEVEL + " - 1.0 * 0.25)",
|
||||
"Explosion power. The more power = the more blocks (area) to explode.");
|
||||
|
||||
this.minBlockStrength = EnchantScaler.read(this, "Settings.Min_Block_Strength",
|
||||
"1.5 - " + Placeholders.ENCHANTMENT_LEVEL + " / 10",
|
||||
"Minimal block strength value for the enchantment to have effect.",
|
||||
"Block strength value is how long it takes to break the block by a hand.",
|
||||
"For example, a Stone has 3.0 strength.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_EXPLOSION_POWER, level -> NumberUtil.format(this.getExplosionPower(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
public double getExplosionPower(int level) {
|
||||
return this.explosionPower.getValue(level);
|
||||
}
|
||||
|
||||
public float getMinBlockStrength(int level) {
|
||||
return (float) minBlockStrength.getValue(level);
|
||||
}
|
||||
|
||||
private boolean isHardEnough(@NotNull Block block, int level) {
|
||||
float strength = block.getType().getHardness();
|
||||
return (strength >= this.getMinBlockStrength(level));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.PICKAXE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
if (!(entity instanceof Player player)) return false;
|
||||
if (EnchantUtils.isBusy()) return false;
|
||||
|
||||
Block block = event.getBlock();
|
||||
if (!this.isHardEnough(block, level)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
float power = (float) this.getExplosionPower(level);
|
||||
|
||||
this.explodeLevel = level;
|
||||
NoCheatPlusHook.exemptBlocks(player);
|
||||
boolean exploded = block.getWorld().createExplosion(block.getLocation(), power, false, true, player);
|
||||
NoCheatPlusHook.unexemptBlocks(player);
|
||||
this.explodeLevel = -1;
|
||||
|
||||
return exploded;
|
||||
}
|
||||
|
||||
// Process explosion event to mine blocks.
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onBlastExplosionEvent(EntityExplodeEvent event) {
|
||||
if (this.explodeLevel <= 0) return;
|
||||
if (!(event.getEntity() instanceof Player player)) return;
|
||||
|
||||
List<Block> blockList = event.blockList();
|
||||
blockList.forEach(block -> {
|
||||
if (block.getLocation().equals(event.getLocation()) || !this.isHardEnough(block, this.explodeLevel)) return;
|
||||
|
||||
EnchantUtils.safeBusyBreak(player, block);
|
||||
});
|
||||
blockList.clear();
|
||||
}
|
||||
|
||||
// Do not damage around entities by enchantment explosion.
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onBlastExplosionDamage(EntityDamageByEntityEvent e) {
|
||||
if (e.getCause() != DamageCause.ENTITY_EXPLOSION) return;
|
||||
if (!(e.getDamager() instanceof Player player)) return;
|
||||
|
||||
e.setCancelled(this.explodeLevel > 0);
|
||||
}
|
||||
|
||||
// Do not reduce item durability for 'exploded' blocks.
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onBlastExplosionItemDamage(PlayerItemDamageEvent e) {
|
||||
e.setCancelled(this.explodeLevel > 0);
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
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.manager.EventListener;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
public class CurseOfBreakingEnchant extends ExcellentEnchant implements GenericEnchant, EventListener, Chanced {
|
||||
|
||||
public static final String ID = "curse_of_breaking";
|
||||
public static final String PLACEHOLDER_DURABILITY_AMOUNT = "%enchantment_durability_amount%";
|
||||
|
||||
private EnchantScaler durabilityAmount;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public CurseOfBreakingEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to consume extra " + PLACEHOLDER_DURABILITY_AMOUNT + " durability points.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"10.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
this.durabilityAmount = EnchantScaler.read(this, "Settings.Durability_Amount",
|
||||
Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Amount of durability points to be taken from the item.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_DURABILITY_AMOUNT, level -> NumberUtil.format(this.getDurabilityAmount(level)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
public int getDurabilityAmount(int level) {
|
||||
return (int) this.durabilityAmount.getValue(level);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BREAKABLE;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onItemDurability(PlayerItemDamageEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (!this.isAvailableToUse(player)) return;
|
||||
|
||||
ItemStack item = event.getItem();
|
||||
int level = EnchantUtils.getLevel(item, this.getBackend());
|
||||
|
||||
if (level < 1) return;
|
||||
if (!this.checkTriggerChance(level)) return;
|
||||
|
||||
int durabilityAmount = this.getDurabilityAmount(level);
|
||||
if (durabilityAmount <= 0) return;
|
||||
|
||||
event.setDamage(event.getDamage() + durabilityAmount);
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockDropItemEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityResurrectEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
|
||||
public class CurseOfMediocrityEnchant extends ExcellentEnchant implements Chanced, BlockDropEnchant, DeathEnchant {
|
||||
|
||||
public static final String ID = "curse_of_mediocrity";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public CurseOfMediocrityEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to disenchant item drops.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "25.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BREAKABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[] {
|
||||
ItemCategory.SWORD, ItemCategory.BOW, ItemCategory.CROSSBOW, ItemCategory.TRIDENT, ItemCategory.TOOL
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getDropPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Chanced getChanceImplementation() {
|
||||
return this.chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrop(@NotNull BlockDropItemEvent event,
|
||||
@NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
event.getItems().forEach(drop -> {
|
||||
ItemStack stack = drop.getItemStack();
|
||||
ItemUtil.mapMeta(stack, meta -> {
|
||||
meta.getEnchants().keySet().forEach(meta::removeEnchant);
|
||||
});
|
||||
drop.setItemStack(stack);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDeath(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, ItemStack item, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResurrect(@NotNull EntityResurrectEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKill(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, @NotNull Player killer, ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
event.getDrops().forEach(stack -> {
|
||||
ItemUtil.mapMeta(stack, meta -> {
|
||||
meta.getEnchants().keySet().forEach(meta::removeEnchant);
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityResurrectEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
|
||||
public class CurseOfMisfortuneEnchant extends ExcellentEnchant implements Chanced, BlockBreakEnchant, DeathEnchant {
|
||||
|
||||
public static final String ID = "curse_of_misfortune";
|
||||
|
||||
private boolean dropExp;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public CurseOfMisfortuneEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to have no drops from blocks or mobs.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0D);
|
||||
this.getDefaults().setConflicts(
|
||||
Enchantment.LOOT_BONUS_BLOCKS.getKey().getKey(),
|
||||
Enchantment.LOOT_BONUS_MOBS.getKey().getKey()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"20.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
this.dropExp = JOption.create("Settings.Drop_Exp", false,
|
||||
"When 'true' allows to drop exp from mobs/blocks.").read(cfg);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
public boolean isDropExp() {
|
||||
return dropExp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[] {
|
||||
ItemCategory.SWORD, ItemCategory.BOW, ItemCategory.CROSSBOW, ItemCategory.TRIDENT, ItemCategory.TOOL
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BREAKABLE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getBreakPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getKillPriority() {
|
||||
return EventPriority.HIGH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
event.setDropItems(false);
|
||||
if (!this.isDropExp()) event.setExpToDrop(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKill(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, @NotNull Player killer, ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
event.getDrops().clear();
|
||||
if (!this.isDropExp()) event.setDroppedExp(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDeath(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, ItemStack item, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResurrect(@NotNull EntityResurrectEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
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.block.BlockDropItemEvent;
|
||||
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.JOption;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nexmedia.engine.lang.LangManager;
|
||||
import su.nexmedia.engine.utils.Colorizer;
|
||||
import su.nexmedia.engine.utils.Colors;
|
||||
import su.nexmedia.engine.utils.LocationUtil;
|
||||
import su.nexmedia.engine.utils.PDCUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
public class DivineTouchEnchant extends ExcellentEnchant implements Chanced, BlockBreakEnchant, BlockDropEnchant, EventListener {
|
||||
|
||||
public static final String ID = "divine_touch";
|
||||
|
||||
private final NamespacedKey key;
|
||||
|
||||
private String spawnerName;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
private Location handleSpawner;
|
||||
|
||||
public DivineTouchEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.key = new NamespacedKey(plugin, "divine_spawner");
|
||||
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to mine spawner.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(1.0);
|
||||
this.getDefaults().setConflicts(SmelterEnchant.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"15.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
|
||||
this.spawnerName = JOption.create("Settings.Spawner_Item.Name",
|
||||
Colors.GREEN + "Mob Spawner " + Colors.GRAY + "(" + Placeholders.GENERIC_TYPE + ")",
|
||||
"Spawner item display name.",
|
||||
"Placeholder '" + Placeholders.GENERIC_TYPE + "' for the mob type."
|
||||
).mapReader(Colorizer::apply).read(cfg);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.PICKAXE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getDropPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getBreakPriority() {
|
||||
return EventPriority.HIGH;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getSpawner(@NotNull CreatureSpawner spawnerBlock) {
|
||||
ItemStack itemSpawner = new ItemStack(Material.SPAWNER);
|
||||
BlockStateMeta stateItem = (BlockStateMeta) itemSpawner.getItemMeta();
|
||||
if (stateItem == null || spawnerBlock.getSpawnedType() == null) return itemSpawner;
|
||||
|
||||
CreatureSpawner spawnerItem = (CreatureSpawner) stateItem.getBlockState();
|
||||
spawnerItem.setSpawnedType(spawnerBlock.getSpawnedType());
|
||||
spawnerItem.update(true);
|
||||
stateItem.setBlockState(spawnerItem);
|
||||
stateItem.setDisplayName(this.spawnerName.replace(Placeholders.GENERIC_TYPE, LangManager.getEntityType(spawnerBlock.getSpawnedType())));
|
||||
itemSpawner.setItemMeta(stateItem);
|
||||
|
||||
PDCUtil.set(itemSpawner, this.key, true);
|
||||
return itemSpawner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrop(@NotNull BlockDropItemEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
BlockState state = event.getBlockState();
|
||||
Block block = state.getBlock();
|
||||
if (this.handleSpawner == null || !this.handleSpawner.equals(block.getLocation())) return false;
|
||||
this.handleSpawner = null;
|
||||
|
||||
if (!(state instanceof CreatureSpawner spawnerBlock)) return false;
|
||||
|
||||
EnchantUtils.popResource(event, this.getSpawner(spawnerBlock));
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
Location location = LocationUtil.getCenter(block.getLocation());
|
||||
UniParticle.of(Particle.VILLAGER_HAPPY).play(location, 0.3, 0.15, 30);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
Block block = event.getBlock();
|
||||
if (!(block.getState() instanceof CreatureSpawner spawnerBlock)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
event.setExpToDrop(0);
|
||||
event.setDropItems(true);
|
||||
this.handleSpawner = block.getLocation();
|
||||
return false; // Do not consume charges
|
||||
}
|
||||
|
||||
// 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().getItem(e.getHand());
|
||||
if (spawner == null || spawner.getType() != Material.SPAWNER || !(spawner.getItemMeta() instanceof BlockStateMeta meta)) return;
|
||||
if (PDCUtil.getBoolean(spawner, this.key).isEmpty()) return;
|
||||
|
||||
CreatureSpawner spawnerItem = (CreatureSpawner) meta.getBlockState();
|
||||
CreatureSpawner spawnerBlock = (CreatureSpawner) block.getState();
|
||||
|
||||
spawnerBlock.setSpawnedType(spawnerItem.getSpawnedType());
|
||||
spawnerBlock.update();
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.PassiveEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PeriodImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class HasteEnchant extends ExcellentEnchant implements Potioned, PassiveEnchant {
|
||||
|
||||
public static final String ID = "haste";
|
||||
|
||||
private PotionImplementation potionImplementation;
|
||||
private PeriodImplementation periodImplementation;
|
||||
|
||||
public HasteEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Grants permanent " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " effect.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.FAST_DIGGING, true);
|
||||
this.periodImplementation = PeriodImplementation.create(this, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PeriodImplementation getPeriodImplementation() {
|
||||
return periodImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrigger(@NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return this.addEffect(entity, level);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
|
||||
public class LuckyMinerEnchant extends ExcellentEnchant implements Chanced, BlockBreakEnchant {
|
||||
|
||||
public static final String ID = "lucky_miner";
|
||||
private static final String PLACEHOLDER_EXP_MODIFIER = "%enchantment_exp_modifier%";
|
||||
|
||||
private EnchantScaler expModifier;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public LuckyMinerEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to gain " + PLACEHOLDER_EXP_MODIFIER + "% more exp from ores.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"30.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 7.0");
|
||||
this.expModifier = EnchantScaler.read(this, "Settings.Exp_Modifier",
|
||||
"1.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 0.5",
|
||||
"Exp modifier value. The original exp amount will be multiplied on this value.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_EXP_MODIFIER, level -> NumberUtil.format(this.getExpModifier(level) * 100D - 100D));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
public double getExpModifier(int level) {
|
||||
return this.expModifier.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.PICKAXE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
double expMod = this.getExpModifier(level);
|
||||
event.setExpToDrop((int) ((double) event.getExpToDrop() * expMod));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
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.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventPriority;
|
||||
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.JOption;
|
||||
import su.nexmedia.engine.utils.values.UniSound;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.InteractEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class ReplanterEnchant extends ExcellentEnchant implements Chanced, InteractEnchant, BlockBreakEnchant {
|
||||
|
||||
public static final String ID = "replanter";
|
||||
|
||||
private boolean replantOnRightClick;
|
||||
private boolean replantOnPlantBreak;
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
private static final Set<Material> CROPS = Set.of(
|
||||
Material.WHEAT_SEEDS, Material.BEETROOT_SEEDS,
|
||||
Material.MELON_SEEDS, Material.PUMPKIN_SEEDS,
|
||||
Material.POTATO, Material.CARROT, Material.NETHER_WART);
|
||||
|
||||
public ReplanterEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Automatically replant crops on right click and when harvest.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "100");
|
||||
this.replantOnRightClick = JOption.create("Settings.Replant.On_Right_Click", true,
|
||||
"When 'true', player will be able to replant crops when right-clicking farmland blocks.").read(cfg);
|
||||
this.replantOnPlantBreak = JOption.create("Settings.Replant.On_Plant_Break", true,
|
||||
"When 'true', crops will be automatically replanted when player break plants with enchanted tool in hand.").read(cfg);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
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
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.HOE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getInteractPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInteract(@NotNull PlayerInteractEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
if (!(entity instanceof Player player)) return false;
|
||||
if (!this.isReplantOnRightClick()) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
// Check for a event hand. We dont want to trigger it twice.
|
||||
if (event.getHand() != EquipmentSlot.HAND) return false;
|
||||
if (event.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 = event.getClickedBlock();
|
||||
if (blockGround == null) return false;
|
||||
if (blockGround.getType() != Material.FARMLAND && blockGround.getType() != Material.SOUL_SAND) 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)) {
|
||||
UniSound.of(seed == Material.NETHER_WART ? Sound.ITEM_NETHER_WART_PLANT : Sound.ITEM_CROP_PLANT).play(player);
|
||||
plugin.getEnchantNMS().sendAttackPacket(player, 0);
|
||||
blockPlant.setType(this.fineSeedsToBlock(seed));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
if (!(entity instanceof Player player)) return false;
|
||||
if (!this.isReplantOnPlantBreak()) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
Block blockPlant = event.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 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,203 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
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.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockDropItemEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
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.BlockStateMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nexmedia.engine.utils.Colorizer;
|
||||
import su.nexmedia.engine.utils.ItemUtil;
|
||||
import su.nexmedia.engine.utils.PDCUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SilkChestEnchant extends ExcellentEnchant implements BlockDropEnchant, EventListener {
|
||||
|
||||
public static final String ID = "silk_chest";
|
||||
|
||||
private String chestName;
|
||||
private List<String> chestLore;
|
||||
private final NamespacedKey keyChest;
|
||||
|
||||
public SilkChestEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Drop chests and saves all its content.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.5);
|
||||
|
||||
this.keyChest = new NamespacedKey(plugin, ID + ".item");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chestName = JOption.create("Settings.Chest_Item.Name", "Chest &7(" + Placeholders.GENERIC_AMOUNT + " items)",
|
||||
"Chest item display name.",
|
||||
"Use '" + Placeholders.GENERIC_AMOUNT + "' for items amount.").mapReader(Colorizer::apply).read(cfg);
|
||||
this.chestLore = JOption.create("Settings.Chest_Item.Lore", new ArrayList<>(),
|
||||
"Chest item lore.",
|
||||
"Use '" + Placeholders.GENERIC_AMOUNT + "' for items amount.").mapReader(Colorizer::apply).read(cfg);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.AXE};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getDropPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
|
||||
public boolean isSilkChest(@NotNull ItemStack item) {
|
||||
return PDCUtil.getBoolean(item, this.keyChest).isPresent();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getSilkChest(@NotNull Chest chest) {
|
||||
ItemStack chestStack = new ItemStack(chest.getType());
|
||||
|
||||
BlockStateMeta stateMeta = (BlockStateMeta) chestStack.getItemMeta();
|
||||
if (stateMeta == null) return chestStack;
|
||||
|
||||
Chest chestItem = (Chest) stateMeta.getBlockState();
|
||||
chestItem.getBlockInventory().setContents(chest.getBlockInventory().getContents());
|
||||
chestItem.update(true);
|
||||
|
||||
int amount = (int) Stream.of(chestItem.getBlockInventory().getContents()).filter(i -> i != null && !i.getType().isAir()).count();
|
||||
|
||||
stateMeta.setBlockState(chestItem);
|
||||
stateMeta.setDisplayName(this.chestName);
|
||||
stateMeta.setLore(this.chestLore);
|
||||
chestStack.setItemMeta(stateMeta);
|
||||
|
||||
ItemUtil.replace(chestStack, str -> str.replace(Placeholders.GENERIC_AMOUNT, String.valueOf(amount)));
|
||||
PDCUtil.set(chestStack, this.keyChest, true);
|
||||
return chestStack;
|
||||
|
||||
// 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) {
|
||||
chest.getWorld().dropItemNaturally(chest.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
|
||||
public boolean onDrop(@NotNull BlockDropItemEvent event,
|
||||
@NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
BlockState state = event.getBlockState();
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (!(state instanceof Chest chest)) return false;
|
||||
|
||||
// Добавляем в сундук обратно предметы из дроп листа, кроме самого сундука.
|
||||
event.getItems().removeIf(drop -> drop.getItemStack().getType() == state.getType() && drop.getItemStack().getAmount() == 1);
|
||||
chest.getBlockInventory().addItem(event.getItems().stream().map(Item::getItemStack).toList().toArray(new ItemStack[0]));
|
||||
event.getItems().clear();
|
||||
|
||||
if (chest.getBlockInventory().isEmpty()) {
|
||||
EnchantUtils.popResource(event, new ItemStack(chest.getType()));
|
||||
return false;
|
||||
}
|
||||
|
||||
EnchantUtils.popResource(event, this.getSilkChest(chest));
|
||||
|
||||
chest.getBlockInventory().clear();
|
||||
|
||||
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;
|
||||
|
||||
chest.setCustomName(null);
|
||||
chest.update(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onSilkChestStore(InventoryClickEvent e) {
|
||||
Inventory inventory = e.getInventory();
|
||||
if (inventory.getType() == InventoryType.CRAFTING || inventory.getType() == InventoryType.CREATIVE) return;
|
||||
|
||||
Player player = (Player) e.getWhoClicked();
|
||||
ItemStack item;
|
||||
if (e.getHotbarButton() >= 0) {
|
||||
item = player.getInventory().getItem(e.getHotbarButton());
|
||||
}
|
||||
else item = e.getCurrentItem();
|
||||
|
||||
if (item == null || item.getType().isAir() || !this.isSilkChest(item)) return;
|
||||
|
||||
Inventory clicked = e.getClickedInventory();
|
||||
if (e.getClick() != ClickType.NUMBER_KEY) {
|
||||
if (clicked != null && clicked.equals(e.getView().getTopInventory())) return;
|
||||
}
|
||||
|
||||
e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onSilkChestHopper(InventoryPickupItemEvent e) {
|
||||
e.setCancelled(this.isSilkChest(e.getItem().getItemStack()));
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.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.block.Container;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockDropItemEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.utils.LocationUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nexmedia.engine.utils.values.UniSound;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SmelterEnchant extends ExcellentEnchant implements Chanced, BlockDropEnchant {
|
||||
|
||||
public static final String ID = "smelter";
|
||||
|
||||
private UniSound sound;
|
||||
private Map<Material, Material> smeltingTable;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public SmelterEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to smelt a block/ore.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.3);
|
||||
this.getDefaults().setConflicts(
|
||||
DivineTouchEnchant.ID,
|
||||
Enchantment.SILK_TOUCH.getKey().getKey()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"25.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 10");
|
||||
|
||||
this.sound = JOption.create("Settings.Sound",UniSound.of(Sound.BLOCK_LAVA_EXTINGUISH),
|
||||
"Sound to play on smelting.",
|
||||
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html").read(cfg);
|
||||
|
||||
this.smeltingTable = JOption.forMap("Settings.Smelting_Table",
|
||||
key -> Material.getMaterial(key.toUpperCase()),
|
||||
(cfg, path, key) -> Material.getMaterial(cfg.getString(path + "." + key, "").toUpperCase()),
|
||||
Map.of(
|
||||
Material.RAW_IRON, Material.IRON_INGOT,
|
||||
Material.RAW_GOLD, Material.GOLD_INGOT
|
||||
),
|
||||
"Table of Original -> Smelted items.",
|
||||
"Syntax: 'Material Source : Material Result'.",
|
||||
"Note: Material source is material name of the dropped item, not the broken block!",
|
||||
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html"
|
||||
).setWriter((cfg, path, map) -> map.forEach((src, to) -> cfg.set(path + "." + src.name(), to.name()))).read(cfg);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.PICKAXE, ItemCategory.AXE, ItemCategory.SHOVEL};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getDropPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrop(@NotNull BlockDropItemEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
// TODO Use furnace recipes & Re-add smelted items instead of setType
|
||||
|
||||
if (event.getBlockState() instanceof Container) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (event.getItems().stream().noneMatch(drop -> this.isSmeltable(drop.getItemStack().getType()))) return false;
|
||||
|
||||
event.getItems().forEach(drop -> {
|
||||
Material material = this.smeltingTable.get(drop.getItemStack().getType());
|
||||
if (material != null) {
|
||||
ItemStack stack = drop.getItemStack();
|
||||
stack.setType(material);
|
||||
drop.setItemStack(stack);
|
||||
}
|
||||
});
|
||||
|
||||
Block block = event.getBlockState().getBlock();
|
||||
if (this.hasVisualEffects()) {
|
||||
Location location = LocationUtil.getCenter(block.getLocation(), true);
|
||||
UniParticle.of(Particle.FLAME).play(location, 0.25, 0.05, 20);
|
||||
this.sound.play(location);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isSmeltable(@NotNull Material material) {
|
||||
return this.smeltingTable.containsKey(material);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockDropItemEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.PlayerUtil;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
|
||||
public class TelekinesisEnchant extends ExcellentEnchant implements Chanced, BlockDropEnchant {
|
||||
|
||||
public static final String ID = "telekinesis";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public TelekinesisEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Moves all blocks loot directly to your inventory.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.75);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this, "100");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.TOOL};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getDropPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrop(@NotNull BlockDropItemEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
if (!(entity instanceof Player player)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
event.getItems().forEach(drop -> {
|
||||
PlayerUtil.addItem(player, drop.getItemStack());
|
||||
});
|
||||
event.getItems().clear();
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockDropItemEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.blocktracker.PlayerBlockTracker;
|
||||
import su.nexmedia.engine.utils.random.Rnd;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.Cleanable;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockDropEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class TreasuresEnchant extends ExcellentEnchant implements Chanced, BlockBreakEnchant, BlockDropEnchant, Cleanable {
|
||||
|
||||
public static final String ID = "treasures";
|
||||
|
||||
private final Predicate<Block> blockTracker;
|
||||
|
||||
private Map<Material, Map<Material, Double>> treasures;
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
private Block handleDrop;
|
||||
|
||||
public TreasuresEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to attempt to find a treasure in mined block.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.1);
|
||||
|
||||
PlayerBlockTracker.initialize();
|
||||
PlayerBlockTracker.BLOCK_FILTERS.add(this.blockTracker = (block) -> {
|
||||
return this.treasures.containsKey(block.getType());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"10.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 4.0");
|
||||
|
||||
this.treasures = new HashMap<>();
|
||||
|
||||
if (cfg.getSection("Settings.Treasures").isEmpty()) {
|
||||
Tag.BASE_STONE_OVERWORLD.getValues().forEach(material -> {
|
||||
cfg.addMissing("Settings.Treasures." + material.name() + ".BONE_MEAL", 2.0);
|
||||
});
|
||||
Tag.DIRT.getValues().forEach(material -> {
|
||||
cfg.addMissing("Settings.Treasures." + material.name() + ".CLAY_BALL", 0.5);
|
||||
cfg.addMissing("Settings.Treasures." + material.name() + ".BOWL", 1.0);
|
||||
cfg.addMissing("Settings.Treasures." + material.name() + ".STICK", 2.0);
|
||||
});
|
||||
Tag.SAND.getValues().forEach(material -> {
|
||||
cfg.addMissing("Settings.Treasures." + material.name() + ".GLOWSTONE_DUST", 1.0);
|
||||
cfg.addMissing("Settings.Treasures." + material.name() + ".GOLD_NUGGET", 0.3);
|
||||
});
|
||||
Tag.LEAVES.getValues().forEach(material -> {
|
||||
cfg.addMissing("Settings.Treasures." + material.name() + ".APPLE", 12.0);
|
||||
});
|
||||
}
|
||||
|
||||
for (String sFromArray : cfg.getSection("Settings.Treasures")) {
|
||||
for (String sFrom : sFromArray.split(",")) {
|
||||
Material mFrom = Material.getMaterial(sFrom.toUpperCase());
|
||||
if (mFrom == null) {
|
||||
plugin.error("[Treasures] Invalid source material '" + sFrom + "' !");
|
||||
continue;
|
||||
}
|
||||
Map<Material, Double> treasuresList = new HashMap<>();
|
||||
|
||||
for (String sTo : cfg.getSection("Settings.Treasures." + sFromArray)) {
|
||||
Material mTo = Material.getMaterial(sTo.toUpperCase());
|
||||
if (mTo == null) {
|
||||
plugin.error("[Treasures] Invalid result material '" + sTo + "' for '" + sFromArray + "' !");
|
||||
continue;
|
||||
}
|
||||
|
||||
double tChance = cfg.getDouble("Settings.Treasures." + sFromArray + "." + sTo);
|
||||
treasuresList.put(mTo, tChance);
|
||||
}
|
||||
this.treasures.put(mFrom, treasuresList);
|
||||
}
|
||||
}
|
||||
|
||||
this.cfg.setComments("Settings.Treasures",
|
||||
"List of source materials (blocks that will drop additional loot). Separated by a comma.",
|
||||
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
PlayerBlockTracker.BLOCK_FILTERS.remove(this.blockTracker);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.PICKAXE, ItemCategory.AXE, ItemCategory.SHOVEL};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getDropPriority() {
|
||||
return EventPriority.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
if (!event.isDropItems()) return false;
|
||||
if (PlayerBlockTracker.isTracked(event.getBlock())) return false;
|
||||
|
||||
this.handleDrop = event.getBlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrop(@NotNull BlockDropItemEvent event, @NotNull LivingEntity player, @NotNull ItemStack item, int level) {
|
||||
if (this.handleDrop != event.getBlock()) return false;
|
||||
this.handleDrop = null;
|
||||
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
this.getTreasures(event.getBlockState().getType()).forEach(treasure -> {
|
||||
EnchantUtils.popResource(event, treasure);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final List<ItemStack> getTreasures(@NotNull Material type) {
|
||||
List<ItemStack> list = new ArrayList<>();
|
||||
Map<Material, Double> treasures = this.treasures.getOrDefault(type, Collections.emptyMap());
|
||||
treasures.forEach((mat, chance) -> {
|
||||
if (mat.isAir() || !mat.isItem() || !Rnd.chance(chance)) return;
|
||||
list.add(new ItemStack(mat));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.JOption;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
import su.nightexpress.excellentenchants.hook.impl.NoCheatPlusHook;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class TunnelEnchant extends ExcellentEnchant implements BlockBreakEnchant {
|
||||
|
||||
public static final String ID = "tunnel";
|
||||
// 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);
|
||||
INTERACTABLE_BLOCKS.add(Material.DEEPSLATE_REDSTONE_ORE);
|
||||
}
|
||||
|
||||
private boolean disableOnSneak;
|
||||
|
||||
public TunnelEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
|
||||
this.getDefaults().setDescription("Mines multiple blocks at once in a certain shape.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(1.0);
|
||||
this.getDefaults().setConflicts(VeinminerEnchant.ID, BlastMiningEnchant.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.disableOnSneak = JOption.create("Settings.Ignore_When_Sneaking", true,
|
||||
"When 'true' the enchantment won't be triggered when sneaking.").read(cfg);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.PICKAXE, ItemCategory.SHOVEL};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.TOOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
if (!(entity instanceof Player player)) return false;
|
||||
if (EnchantUtils.isBusy()) return false;
|
||||
if (this.disableOnSneak && player.isSneaking()) return false;
|
||||
|
||||
Block block = event.getBlock();
|
||||
if (block.getType().isInteractable() && !INTERACTABLE_BLOCKS.contains(block.getType())) return false;
|
||||
if (block.getDrops(item).isEmpty()) return false;
|
||||
|
||||
|
||||
final List<Block> lastTwoTargetBlocks = player.getLastTwoTargetBlocks(null, 10);
|
||||
if (lastTwoTargetBlocks.size() != 2 || !lastTwoTargetBlocks.get(1).getType().isOccluding()) {
|
||||
return false;
|
||||
}
|
||||
final Block targetBlock = lastTwoTargetBlocks.get(1);
|
||||
final Block adjacentBlock = lastTwoTargetBlocks.get(0);
|
||||
final BlockFace dir = targetBlock.getFace(adjacentBlock);
|
||||
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;
|
||||
|
||||
NoCheatPlusHook.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 (dir == BlockFace.UP || dir == BlockFace.DOWN) {
|
||||
blockAdd = block.getLocation().clone().add(xAdd, 0, zAdd).getBlock();
|
||||
} else {
|
||||
blockAdd = block.getLocation().clone().add(isZ ? 0 : xAdd, zAdd, isZ ? xAdd : 0).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;
|
||||
|
||||
EnchantUtils.safeBusyBreak(player, blockAdd);
|
||||
}
|
||||
|
||||
NoCheatPlusHook.unexemptBlocks(player);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.tool;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
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.JOption;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.BlockBreakEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.ItemCategory;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
import su.nightexpress.excellentenchants.hook.impl.NoCheatPlusHook;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class VeinminerEnchant extends ExcellentEnchant implements BlockBreakEnchant {
|
||||
|
||||
public static final String ID = "veinminer";
|
||||
|
||||
private static final BlockFace[] AREA = {
|
||||
BlockFace.UP, BlockFace.DOWN, BlockFace.EAST,
|
||||
BlockFace.WEST, BlockFace.SOUTH, BlockFace.NORTH
|
||||
};
|
||||
|
||||
private static final String PLACEHOLDER_BLOCK_LIMIT = "%enchantment_block_limit%";
|
||||
|
||||
private EnchantScaler blocksLimit;
|
||||
private Set<Material> blocksAffected;
|
||||
|
||||
public VeinminerEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
|
||||
this.getDefaults().setDescription("Mines up to " + PLACEHOLDER_BLOCK_LIMIT + " blocks of the ore vein at once.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.3);
|
||||
this.getDefaults().setConflicts(BlastMiningEnchant.ID, TunnelEnchant.ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.blocksLimit = EnchantScaler.read(this, "Settings.Blocks.Max_At_Once",
|
||||
"6 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"How much amount of blocks can be destroted at single use?");
|
||||
|
||||
this.blocksAffected = JOption.forSet("Settings.Blocks.Affected",
|
||||
str -> Material.getMaterial(str.toUpperCase()),
|
||||
() -> {
|
||||
Set<Material> set = new HashSet<>();
|
||||
set.addAll(Tag.COAL_ORES.getValues());
|
||||
set.addAll(Tag.COPPER_ORES.getValues());
|
||||
set.addAll(Tag.DIAMOND_ORES.getValues());
|
||||
set.addAll(Tag.EMERALD_ORES.getValues());
|
||||
set.addAll(Tag.GOLD_ORES.getValues());
|
||||
set.addAll(Tag.IRON_ORES.getValues());
|
||||
set.addAll(Tag.LAPIS_ORES.getValues());
|
||||
set.addAll(Tag.REDSTONE_ORES.getValues());
|
||||
set.add(Material.NETHER_GOLD_ORE);
|
||||
set.add(Material.NETHER_QUARTZ_ORE);
|
||||
return set;
|
||||
},
|
||||
"List of blocks, that will be affected by this enchantment.",
|
||||
"https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html"
|
||||
).setWriter((cfg, path, set) -> cfg.set(path, set.stream().map(Enum::name).toList())).read(cfg);
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_BLOCK_LIMIT, level -> String.valueOf(this.getBlocksLimit(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<Material> getBlocksAffected() {
|
||||
return this.blocksAffected;
|
||||
}
|
||||
|
||||
public int getBlocksLimit(int level) {
|
||||
return (int) this.blocksLimit.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ItemCategory[] getFitItemTypes() {
|
||||
return new ItemCategory[]{ItemCategory.PICKAXE};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
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 -> EnchantUtils.safeBusyBreak(player, ore));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBreak(@NotNull BlockBreakEvent event, @NotNull LivingEntity entity, @NotNull ItemStack tool, int level) {
|
||||
if (!(entity instanceof Player player)) return false;
|
||||
if (EnchantUtils.isBusy()) return false;
|
||||
|
||||
Block block = event.getBlock();
|
||||
if (block.getDrops(tool, player).isEmpty()) return false;
|
||||
if (!this.getBlocksAffected().contains(block.getType())) return false;
|
||||
|
||||
NoCheatPlusHook.exemptBlocks(player);
|
||||
this.vein(player, block, level);
|
||||
NoCheatPlusHook.unexemptBlocks(player);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.universal;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.inventory.PrepareAnvilEvent;
|
||||
import org.bukkit.inventory.AnvilInventory;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
public class CurseOfFragilityEnchant extends ExcellentEnchant implements GenericEnchant, EventListener {
|
||||
|
||||
public static final String ID = "curse_of_fragility";
|
||||
|
||||
public CurseOfFragilityEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Prevents an item from being grindstoned or anviled.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0D);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BREAKABLE;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onItemAnvil(PrepareAnvilEvent e) {
|
||||
AnvilInventory inventory = e.getInventory();
|
||||
ItemStack first = inventory.getItem(0);
|
||||
ItemStack second = inventory.getItem(1);
|
||||
|
||||
boolean cursedFirst = (first != null && EnchantUtils.getLevel(first, this.getBackend()) >= 1);
|
||||
boolean cursedSecond = (second != null && EnchantUtils.getLevel(second, this.getBackend()) >= 1);
|
||||
|
||||
if (cursedFirst || cursedSecond) {
|
||||
e.setResult(null);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onItemGrindstoneClick(InventoryClickEvent e) {
|
||||
Inventory inventory = e.getInventory();
|
||||
if (inventory.getType() != InventoryType.GRINDSTONE) return;
|
||||
|
||||
this.stopGrindstone(inventory);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onItemGrindstoneDrag(InventoryDragEvent e) {
|
||||
Inventory inventory = e.getInventory();
|
||||
if (inventory.getType() != InventoryType.GRINDSTONE) return;
|
||||
|
||||
this.stopGrindstone(inventory);
|
||||
}
|
||||
|
||||
private void stopGrindstone(@NotNull Inventory inventory) {
|
||||
plugin.getScheduler().runTask(plugin, () -> {
|
||||
ItemStack first = inventory.getItem(0);
|
||||
ItemStack second = inventory.getItem(1);
|
||||
|
||||
boolean cursedFirst = (first != null && EnchantUtils.getLevel(first, this.getBackend()) >= 1);
|
||||
boolean cursedSecond = (second != null && EnchantUtils.getLevel(second, this.getBackend()) >= 1);
|
||||
|
||||
if (cursedFirst || cursedSecond) {
|
||||
inventory.setItem(2, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.universal;
|
||||
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerItemDamageEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.Damageable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nexmedia.engine.utils.values.UniSound;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
public class RestoreEnchant extends ExcellentEnchant implements GenericEnchant, Chanced, EventListener {
|
||||
|
||||
public static final String ID = "restore";
|
||||
public static final String PLACEHOLDER_DURABILITY_RESTORE = "%durability_restore%";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private EnchantScaler durabilityRestore;
|
||||
|
||||
public RestoreEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to save item from breaking back to " + PLACEHOLDER_DURABILITY_RESTORE + "%");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"35.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 8");
|
||||
|
||||
this.durabilityRestore = EnchantScaler.read(this, "Settings.Durability_Restoration",
|
||||
"25.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 5",
|
||||
"Amount of durability (in percent of item max) to be restored.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_DURABILITY_RESTORE, level -> NumberUtil.format(this.getDurabilityRestore(level)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BREAKABLE;
|
||||
}
|
||||
|
||||
public double getDurabilityRestore(int level) {
|
||||
return this.durabilityRestore.getValue(level);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onItemDamage(PlayerItemDamageEvent event) {
|
||||
ItemStack item = event.getItem();
|
||||
if (!(item.getItemMeta() instanceof Damageable damageable)) return;
|
||||
|
||||
int damage = event.getDamage();
|
||||
int maxDurability = item.getType().getMaxDurability();
|
||||
if (damageable.getDamage() + damage < maxDurability) return;
|
||||
|
||||
int level = EnchantUtils.getLevel(item, this.getBackend());
|
||||
if (level <= 0) return;
|
||||
|
||||
if (this.isOutOfCharges(item)) return;
|
||||
if (!this.checkTriggerChance(level)) return;
|
||||
|
||||
event.setCancelled(true);
|
||||
this.consumeChargesNoUpdate(item, level);
|
||||
|
||||
double restorePercent = 100D - this.getDurabilityRestore(level);
|
||||
int restored = (int) (maxDurability * (restorePercent / 100D));
|
||||
|
||||
damageable.setDamage(restored);
|
||||
item.setItemMeta(damageable);
|
||||
EnchantUtils.remove(item, this.getBackend());
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniSound.of(Sound.ITEM_TOTEM_USE).play(event.getPlayer());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.universal;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.manager.EventListener;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.GenericEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SoulboundEnchant extends ExcellentEnchant implements GenericEnchant, EventListener {
|
||||
|
||||
public static final String ID = "soulbound";
|
||||
|
||||
public SoulboundEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Protects from being dropped on death.");
|
||||
this.getDefaults().setLevelMax(1);
|
||||
this.getDefaults().setTier(0.8);
|
||||
this.getDefaults().setConflicts(Enchantment.VANISHING_CURSE.getKey().getKey());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.BREAKABLE;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDeath(@NotNull PlayerDeathEvent deathEvent) {
|
||||
Player player = deathEvent.getEntity();
|
||||
if (!this.isAvailableToUse(player)) return;
|
||||
if (deathEvent.getKeepInventory()) return;
|
||||
|
||||
List<ItemStack> saveList = new ArrayList<>();
|
||||
Location location = player.getLocation();
|
||||
World world = player.getWorld();
|
||||
|
||||
deathEvent.getDrops().removeIf(drop -> {
|
||||
if (EnchantUtils.getLevel(drop, this.getBackend()) > 0) {
|
||||
if (this.isOutOfCharges(drop)) return false;
|
||||
|
||||
saveList.add(drop);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (saveList.isEmpty()) return;
|
||||
|
||||
this.plugin.runTask(task -> {
|
||||
saveList.forEach(save -> {
|
||||
if (player.getInventory().firstEmpty() == -1) {
|
||||
world.dropItemNaturally(location, save);
|
||||
}
|
||||
else {
|
||||
this.consumeChargesNoUpdate(save, EnchantUtils.getLevel(save, this.getBackend()));
|
||||
player.getInventory().addItem(save);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
|
||||
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityResurrectEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.DeathEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
public class CurseOfDeathEnchant extends ExcellentEnchant implements DeathEnchant, Chanced {
|
||||
|
||||
public static final String ID = "curse_of_death";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
public CurseOfDeathEnchant(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("When killing players, you have a chance of dying too.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
|
||||
this.chanceImplementation = ChanceImplementation.create(this, Placeholders.ENCHANTMENT_LEVEL + " * 0.1");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Chanced getChanceImplementation() {
|
||||
return this.chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDeath(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, ItemStack item, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResurrect(@NotNull EntityResurrectEvent event, @NotNull LivingEntity entity, @NotNull ItemStack item, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKill(@NotNull EntityDeathEvent event, @NotNull LivingEntity entity, @NotNull Player killer, ItemStack weapon, int level) {
|
||||
if (!(entity instanceof Player dead)) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
|
||||
killer.setHealth(0D);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.api.config.JOption;
|
||||
import su.nexmedia.engine.utils.NumberUtil;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.config.EnchantScaler;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class EnchantBaneOfNetherspawn extends ExcellentEnchant implements CombatEnchant {
|
||||
|
||||
public static final String ID = "bane_of_netherspawn";
|
||||
|
||||
private static final String PLACEHOLDER_DAMAGE = "%enchantment_damage%";
|
||||
private static final Set<EntityType> ENTITY_TYPES = Set.of(
|
||||
EntityType.BLAZE, EntityType.MAGMA_CUBE,
|
||||
EntityType.WITHER_SKELETON, EntityType.GHAST, EntityType.WITHER,
|
||||
EntityType.PIGLIN, EntityType.PIGLIN_BRUTE,
|
||||
EntityType.ZOGLIN, EntityType.HOGLIN,
|
||||
EntityType.STRIDER, EntityType.ZOMBIFIED_PIGLIN
|
||||
);
|
||||
|
||||
private boolean damageModifier;
|
||||
private EnchantScaler damageFormula;
|
||||
|
||||
public EnchantBaneOfNetherspawn(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription("Inflicts " + PLACEHOLDER_DAMAGE + " more damage to nether mobs.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.damageModifier = JOption.create("Settings.Damage.As_Modifier", false,
|
||||
"When 'true' multiplies the damage. When 'false' sums plain values.").read(cfg);
|
||||
this.damageFormula = EnchantScaler.read(this, "Settings.Damage.Amount",
|
||||
"0.5 * " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
"Amount of additional damage.");
|
||||
|
||||
this.addPlaceholder(PLACEHOLDER_DAMAGE, level -> NumberUtil.format(this.getDamageModifier(level)));
|
||||
}
|
||||
|
||||
public double getDamageModifier(int level) {
|
||||
return this.damageFormula.getValue(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!ENTITY_TYPES.contains(victim.getType())) return false;
|
||||
|
||||
double damageEvent = event.getDamage();
|
||||
double damageAdd = this.getDamageModifier(level);
|
||||
event.setDamage(this.damageModifier ? damageEvent * damageAdd : damageEvent + damageAdd);
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.of(Particle.SMOKE_NORMAL).play(victim.getEyeLocation(), 0.25, 0.1, 30);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class EnchantBlindness extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
|
||||
|
||||
public static final String ID = "blindness";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public EnchantBlindness(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to apply " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) on hit.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"15.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 3");
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.BLINDNESS, false,
|
||||
"3.5 + " + Placeholders.ENCHANTMENT_LEVEL,
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getAttackPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.addEffect(victim, level)) return false;
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.of(Particle.SMOKE_NORMAL).play(victim.getEyeLocation(), 0.25, 0.1, 30);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Potioned;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.PotionImplementation;
|
||||
|
||||
public class EnchantConfusion extends ExcellentEnchant implements Chanced, Potioned, CombatEnchant {
|
||||
|
||||
public static final String ID = "confusion";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
private PotionImplementation potionImplementation;
|
||||
|
||||
public EnchantConfusion(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to apply " + Placeholders.ENCHANTMENT_POTION_TYPE + " " + Placeholders.ENCHANTMENT_POTION_LEVEL + " (" + Placeholders.ENCHANTMENT_POTION_DURATION + "s.) on hit.");
|
||||
this.getDefaults().setLevelMax(3);
|
||||
this.getDefaults().setTier(0.1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"15.0 * " + Placeholders.ENCHANTMENT_LEVEL);
|
||||
this.potionImplementation = PotionImplementation.create(this, PotionEffectType.CONFUSION, false,
|
||||
"5.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 1.5",
|
||||
Placeholders.ENCHANTMENT_LEVEL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PotionImplementation getPotionImplementation() {
|
||||
return potionImplementation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getAttackPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!this.addEffect(victim, level)) return false;
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.itemCrack(Material.ROTTEN_FLESH).play(victim.getEyeLocation(), 0.25, 0.1, 30);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package su.nightexpress.excellentenchants.enchantment.impl.weapon;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.enchantments.EnchantmentTarget;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nexmedia.engine.utils.values.UniParticle;
|
||||
import su.nightexpress.excellentenchants.ExcellentEnchants;
|
||||
import su.nightexpress.excellentenchants.Placeholders;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.meta.Chanced;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.type.CombatEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.meta.ChanceImplementation;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class EnchantCure extends ExcellentEnchant implements Chanced, CombatEnchant {
|
||||
|
||||
public static final String ID = "cure";
|
||||
|
||||
private ChanceImplementation chanceImplementation;
|
||||
|
||||
private static final Set<EntityType> CUREABLE = Sets.newHashSet(EntityType.ZOMBIFIED_PIGLIN, EntityType.ZOMBIE_VILLAGER);
|
||||
|
||||
public EnchantCure(@NotNull ExcellentEnchants plugin) {
|
||||
super(plugin, ID);
|
||||
this.getDefaults().setDescription(Placeholders.ENCHANTMENT_CHANCE + "% chance to cure Zombified Piglins and Zombie Villagers on hit.");
|
||||
this.getDefaults().setLevelMax(5);
|
||||
this.getDefaults().setTier(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
super.loadSettings();
|
||||
this.chanceImplementation = ChanceImplementation.create(this,
|
||||
"20.0 + " + Placeholders.ENCHANTMENT_LEVEL + " * 8");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChanceImplementation getChanceImplementation() {
|
||||
return chanceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public EnchantmentTarget getCategory() {
|
||||
return EnchantmentTarget.WEAPON;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EventPriority getAttackPriority() {
|
||||
return EventPriority.HIGHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAttack(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
if (!CUREABLE.contains(victim.getType())) return false;
|
||||
if (!this.checkTriggerChance(level)) return false;
|
||||
if (!(damager instanceof Player player)) return false;
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
if (this.hasVisualEffects()) {
|
||||
UniParticle.of(Particle.CLOUD).play(victim.getEyeLocation(), 0.25, 0.1, 30);
|
||||
}
|
||||
|
||||
if (victim instanceof PigZombie pigZombie) {
|
||||
victim.getWorld().spawn(victim.getLocation(), Piglin.class);
|
||||
victim.remove();
|
||||
}
|
||||
else if (victim instanceof ZombieVillager zombieVillager) {
|
||||
zombieVillager.setConversionTime(1);
|
||||
zombieVillager.setConversionPlayer(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onProtect(@NotNull EntityDamageByEntityEvent event, @NotNull LivingEntity damager, @NotNull LivingEntity victim, @NotNull ItemStack weapon, int level) {
|
||||
return false;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user