diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7b016a8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "automatic" +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index fc52ce1..ec1bec2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.zenox evocraft - 1.2.0-ALPHA + 1.3.0-ALPHA jar EvoCraft @@ -96,25 +96,25 @@ io.papermc.paper paper-api - 1.19.3-R0.1-SNAPSHOT + 1.20.2-R0.1-SNAPSHOT provided org.spigotmc spigot - 1.19-R0.1-SNAPSHOT + 1.20.2-R0.1-SNAPSHOT provided com.sk89q.worldguard worldguard-bukkit - 7.0.7 + 7.0.9 provided - com.github.Archy-X - AureliumSkills - Beta1.3.6 + dev.aurelium + auraskills-api-bukkit + 2.2.4 provided @@ -122,6 +122,11 @@ commons-lang3 3.12.0 + + commons-io + commons-io + 2.7 + com.moandjiezana.toml toml4j @@ -130,24 +135,30 @@ com.comphenix.protocol ProtocolLib - 4.7.0 + 5.1.0 provided com.ticxo.modelengine api - R3.0.1 + R3.1.6 provided - de.studiocode.invui - InvUI - 0.8.2 + xyz.xenondevs.invui + invui + 1.23 + pom + + + com.google.guava + guava + 23.5-jre net.citizensnpcs citizens-main - 2.0.30-SNAPSHOT + 2.0.33-SNAPSHOT jar provided @@ -163,5 +174,10 @@ 1.7 provided + + com.mojang + authlib + 3.5.41 + diff --git a/src/main/java/me/zenox/evocraft/EvoCraft.java b/src/main/java/me/zenox/evocraft/EvoCraft.java index dd0f236..cfb9680 100644 --- a/src/main/java/me/zenox/evocraft/EvoCraft.java +++ b/src/main/java/me/zenox/evocraft/EvoCraft.java @@ -1,32 +1,32 @@ package me.zenox.evocraft; -import com.archyx.aureliumskills.api.AureliumAPI; -import com.archyx.aureliumskills.modifier.Modifiers; -import com.archyx.aureliumskills.ui.ActionBar; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolManager; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import de.studiocode.invui.gui.structure.Structure; -import de.studiocode.invui.item.builder.ItemBuilder; +import dev.aurelium.auraskills.api.AuraSkillsApi; +import dev.aurelium.auraskills.api.AuraSkillsBukkit; import me.zenox.evocraft.abilities.AbilityRegistry; import me.zenox.evocraft.attribute.AttributeRegistry; import me.zenox.evocraft.command.Command; import me.zenox.evocraft.data.ConfigLoader; import me.zenox.evocraft.data.LanguageLoader; +import me.zenox.evocraft.data.PlayerDataManager; import me.zenox.evocraft.enchant.EnchantRegistry; import me.zenox.evocraft.events.*; +import me.zenox.evocraft.gameclass.ClassAbilityListener; import me.zenox.evocraft.item.ItemRegistry; import me.zenox.evocraft.item.VanillaItem; import me.zenox.evocraft.network.GlowFilter; import me.zenox.evocraft.recipe.RecipeRegistry; -import me.zenox.evocraft.story.ChapterManager; import me.zenox.evocraft.util.Util; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.Material; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; +import xyz.xenondevs.invui.gui.structure.Structure; +import xyz.xenondevs.invui.item.builder.ItemBuilder; public final class EvoCraft extends JavaPlugin { @@ -36,12 +36,12 @@ public final class EvoCraft extends JavaPlugin { private static Permission perms = null; public boolean isUsingWorldGuard; - public static Modifiers modifiers; private static LanguageLoader languageLoader; private static ConfigLoader configLoader; private static ProtocolManager protocolManager; - private static ChapterManager chapterManager; - private static ActionBar actionBar; + private static PlayerDataManager playerDataManager; + private static AuraSkillsApi auraSkillsApi; + private static AuraSkillsBukkit auraSkillsBukkit; public static EvoCraft getPlugin() { return plugin; @@ -50,6 +50,7 @@ public static EvoCraft getPlugin() { @Override public void onEnable() { + long startTime = System.currentTimeMillis(); plugin = this; plugin.getLogger().info("EvoCraft v" + plugin.getDescription().getVersion() + " loaded."); @@ -78,12 +79,13 @@ public void onEnable() { return; } - modifiers = new Modifiers(AureliumAPI.getPlugin()); - actionBar = AureliumAPI.getPlugin().getActionBar(); + auraSkillsApi = AuraSkillsApi.get(); + auraSkillsBukkit = AuraSkillsBukkit.get(); + + playerDataManager = new PlayerDataManager(); configLoader = new ConfigLoader(plugin); languageLoader = new LanguageLoader(plugin); - chapterManager = new ChapterManager(plugin); registerGlobalGUIItems(); @@ -102,6 +104,7 @@ public void onEnable() { registerListeners(); + Util.logToConsole("v" + plugin.getDescription().getVersion() + " enabled in &e" + (System.currentTimeMillis() - startTime) + "&fms."); } private void registerListeners() { @@ -110,6 +113,7 @@ private void registerListeners() { new InventoryListener(plugin); new DimensionLocker(plugin); new DeathManager(plugin); + new ClassAbilityListener(plugin); } private boolean setupEconomy() { @@ -163,13 +167,6 @@ public static Permission getPermissions() { return perms; } - public static ChapterManager getChapterManager() { - return chapterManager; - } - - public static ActionBar getActionBar() { - return actionBar; - } public void reload() { this.reloadConfig(); this.languageLoader = new LanguageLoader(this); @@ -177,6 +174,8 @@ public void reload() { @Override public void onDisable() { - // Plugin shutdown logic + long startTime = System.currentTimeMillis(); + playerDataManager.shutdown(); + Util.logToConsole("v" + plugin.getDescription().getVersion() + " disabled in &e" + (System.currentTimeMillis() - startTime) + "&fms."); } } diff --git a/src/main/java/me/zenox/evocraft/Slot.java b/src/main/java/me/zenox/evocraft/Slot.java index d5e0966..7ae2cfe 100644 --- a/src/main/java/me/zenox/evocraft/Slot.java +++ b/src/main/java/me/zenox/evocraft/Slot.java @@ -42,10 +42,10 @@ public enum Slot { * @return The list of unique abilities that the player possesses */ @Deprecated - public static List uniqueEquipped(Player p) { + public static List> uniqueEquipped(Player p) { List items = Arrays.stream(new ItemStack[]{MAIN_HAND.item(p).get(0), OFF_HAND.item(p).get(0), HEAD.item(p).get(0), CHEST.item(p).get(0), LEGS.item(p).get(0), FEET.item(p).get(0)}) .filter(Objects::nonNull).toList(); - List abilities = new ArrayList<>(); + List> abilities = new ArrayList<>(); items.stream() .map(ComplexItemStack::of) .forEach((complexItemStack) -> abilities.addAll(complexItemStack.getAbilities())); diff --git a/src/main/java/me/zenox/evocraft/abilities/Ability.java b/src/main/java/me/zenox/evocraft/abilities/Ability.java index 586ab3e..bf3063a 100644 --- a/src/main/java/me/zenox/evocraft/abilities/Ability.java +++ b/src/main/java/me/zenox/evocraft/abilities/Ability.java @@ -1,97 +1,63 @@ package me.zenox.evocraft.abilities; -import com.archyx.aureliumskills.api.AureliumAPI; -import me.zenox.evocraft.Slot; +import dev.aurelium.auraskills.api.user.SkillsUser; import me.zenox.evocraft.EvoCraft; import me.zenox.evocraft.data.TranslatableList; import me.zenox.evocraft.data.TranslatableText; -import me.zenox.evocraft.item.ComplexItemStack; -import me.zenox.evocraft.util.TriConsumer; import me.zenox.evocraft.util.Util; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import static me.zenox.evocraft.abilities.ClassAbility.SaveState; public abstract class Ability { - public static final List registeredAbilities = new ArrayList<>(); + public static final List> registeredAbilities = new ArrayList<>(); + public static final CooldownManager cooldownManager = new CooldownManager(); private final TranslatableText name; private final String id; - private final int manaCost; - private final double cooldown; - - private final Class eventType; - private final Slot slot; - private TranslatableList lore; + @SaveState + private int manaCost; + @SaveState + private double cooldown; private final boolean isPassive; + private TranslatableList lore; - private TriConsumer executable; - - protected Ability(String id, int manaCost, double cooldown, Slot slot) { - this(id, manaCost, cooldown, slot, false); - this.executable = this::runExecutable; - } - - protected Ability(String id, int manaCost, double cooldown, Slot slot, TriConsumer executable) { - this(id, manaCost, cooldown, slot, false); - this.executable = executable; - } - - protected Ability(AbilitySettings settings){ - this(settings.getId(), settings.getManaCost(), settings.getCooldown(), settings.getSlot(), settings.isPassive()); - } - - protected Ability(AbilitySettings settings, TriConsumer executable){ - this(settings.getId(), settings.getManaCost(), settings.getCooldown(), settings.getSlot(), settings.isPassive()); - this.executable = executable; + public Ability(String id, int manaCost, double cooldown, boolean isPassive) { + this.name = new TranslatableText(TranslatableText.Type.ABILITY_NAME + "-" + id); + this.id = id; + this.manaCost = manaCost; + this.cooldown = cooldown; + this.lore = new TranslatableList(TranslatableText.Type.ABILITY_LORE + "-" + id); + this.isPassive = isPassive; } /** - * Internal constructor because exectuable go brr + * method getAbility
+ * gets the ability corresponding to the id * - * @param id The unique identifier of the ability - * @param manaCost The mana cost-per usage of the ability - * @param cooldown The cooldown of the ability, how long before it can be used again - * @param slot The slot that the item that contains the ability has to be in, i.e. main hand, head, etc - * @param isPassive Whether the ability is passive + * @param id the id to search for + * @return the ability- null if not found */ - private Ability(String id, int manaCost, double cooldown, Slot slot, boolean isPassive) { - this.id = id; - this.name = new TranslatableText(TranslatableText.Type.ABILITY_NAME + "-" + id); - this.lore = new TranslatableList(TranslatableText.Type.ABILITY_LORE + "-" + id); - this.cooldown = cooldown; - this.manaCost = manaCost; - this.slot = slot; - this.isPassive = isPassive; - - this.eventType = (Class) getType(); - if(this.eventType == null) throw new NullPointerException("Event type is null"); - - for (Ability ability : - registeredAbilities) { - if (ability.getId().equalsIgnoreCase(id)) { - Util.logToConsole("Duplicate Ability ID: " + id + " | Exact Match: " + ability.equals(this)); - throw new IllegalArgumentException("Ability ID cannot be duplicate"); - } - } - - Ability.registeredAbilities.add(this); + @Nullable + public static Ability getAbility(String id) { + for (Ability ability : registeredAbilities) if (ability.getId().equals(id)) return ability; + return null; } - private Type getType() { + protected Type getType() { Class clazz = getClass(); while (clazz != null) { Type type = clazz.getGenericSuperclass(); @@ -103,19 +69,6 @@ private Type getType() { return null; } - /** - * method getAbility
- * gets the ability corresponding to the id - * - * @param id the id to search for - * @return the ability- null if not found - */ - @Nullable - public static Ability getAbility(String id) { - for (Ability ability : registeredAbilities) if (ability.getId().equals(id)) return ability; - return null; - } - public String getDisplayName() { return name.toString(); } @@ -133,24 +86,9 @@ protected void setLore(TranslatableList list) { this.lore = list; } - public void useAbility(Event event) { - if (!this.eventType.isInstance(event)) return; - T e = (T) event; - if (!checkEvent(e)) return; - Player p = getPlayerOfEvent(e); - List items = getItem(p, e); - ItemStack item = null; - - // Perhaps change this in the future to support passing multiple items to the consumer - for(ItemStack i : items) { - if (i == null || i.getType() == Material.AIR || i.getItemMeta() == null) continue; - if (!ComplexItemStack.of(i).getAbilities().contains(this)) continue; - item = i; - break; - } - - if(item == null) return; + public abstract void useAbility(Event event); + protected boolean isAbilityOnCooldown(@NotNull Player p) { PersistentDataContainer container = p.getPersistentDataContainer(); NamespacedKey cooldownKey = new NamespacedKey(EvoCraft.getPlugin(), getId() + "_cooldown"); Double cooldown; @@ -162,28 +100,43 @@ public void useAbility(Event event) { container.set(cooldownKey, PersistentDataType.DOUBLE, cooldown); } - // If the ability is on cooldown, return - if (cooldown != null && Math.ceil((cooldown - System.currentTimeMillis()) / 1000) > 0) { - if (!isPassive) Util.sendActionBar(p, ChatColor.WHITE + "" + ChatColor.BOLD + "ABILITY ON COOLDOWN (" + ChatColor.RED + Math.ceil((cooldown - System.currentTimeMillis()) / 100)/10 + "s" + ChatColor.WHITE + ")"); - return; - } + return cooldown != null && Math.ceil((cooldown - System.currentTimeMillis()) / 1000) > 0; + } - if (this.manaCost > 0) { - int resultingMana = ((int) AureliumAPI.getMana(p)) - manaCost; - if (resultingMana < 0) { - if (!isPassive) Util.sendActionBar(p, ChatColor.RED + "" + ChatColor.BOLD + "NOT ENOUGH MANA"); - return; - } else { - AureliumAPI.setMana(p, AureliumAPI.getMana(p) - manaCost); - } + protected void sendCooldownMessage(Player p) { + if (!isPassive) { + Util.sendActionBar(p, ChatColor.WHITE + "" + ChatColor.BOLD + "ABILITY ON COOLDOWN (" + ChatColor.RED + Math.ceil((getCooldownEndTime(p) - System.currentTimeMillis()) / 100) / 10 + "s" + ChatColor.WHITE + ")"); } + } + + protected double getCooldownEndTime(@NotNull Player p) { + PersistentDataContainer container = p.getPersistentDataContainer(); + NamespacedKey cooldownKey = new NamespacedKey(EvoCraft.getPlugin(), getId() + "_cooldown"); + return container.get(cooldownKey, PersistentDataType.DOUBLE); + } - //AureliumAPI.getPlugin().getActionBar().setPaused(p, 20); - String manaMessage = this.manaCost > 0 ? ChatColor.AQUA + "-" + manaCost + " Mana " + "(" + ChatColor.GOLD + name + ChatColor.AQUA + ")" : ChatColor.GOLD + "Used " + name; - if(!isPassive) Util.sendActionBar(p, manaMessage); + protected boolean notEnoughMana(Player p, int requiredMana) { + SkillsUser user = Util.getSkillsUser(p); + return ((int) user.getMana()) < requiredMana; + } - this.executable.accept(e, p, item); + protected void sendManaInsufficientMessage(Player p) { + if (!isPassive) Util.sendActionBar(p, ChatColor.RED + "" + ChatColor.BOLD + "NOT ENOUGH MANA"); + } + protected void deductMana(Player p, int manaCost) { + SkillsUser user = Util.getSkillsUser(p); + user.setMana(user.getMana() - manaCost); + } + + protected void showMessage(Player p, String msg) { + String manaMessage = manaCost > 0 ? ChatColor.AQUA + "-" + manaCost + " Mana " + "(" + ChatColor.GOLD + name + ChatColor.AQUA + ")" : ChatColor.GOLD + "Used " + name; + if (!isPassive) Util.sendActionBar(p, manaMessage + msg); + } + + protected void setAbilityCooldown(Player p) { + PersistentDataContainer container = p.getPersistentDataContainer(); + NamespacedKey cooldownKey = new NamespacedKey(EvoCraft.getPlugin(), getId() + "_cooldown"); container.set(cooldownKey, PersistentDataType.DOUBLE, System.currentTimeMillis() + (getCooldown() * 1000)); } @@ -191,12 +144,6 @@ protected void runExecutable(T e, Player p, ItemStack itemStack) { Util.sendMessage(p, "Used the " + this.id + " ability"); } - abstract boolean checkEvent(T e); - - abstract Player getPlayerOfEvent(T e); - - abstract List getItem(Player p, T e); - public double getCooldown() { return this.cooldown; } @@ -209,15 +156,16 @@ public String getId() { return this.id; } - public Slot getSlot() { - return this.slot; - } - public boolean isPassive() { return isPassive; } - public Class getEventType() { - return eventType; + public void setManaCost(int manaCost) { + this.manaCost = manaCost; } + + public void setCooldown(double cooldown) { + this.cooldown = cooldown; + } + } diff --git a/src/main/java/me/zenox/evocraft/abilities/AbilityRegistry.java b/src/main/java/me/zenox/evocraft/abilities/AbilityRegistry.java index de08a42..e7c795f 100644 --- a/src/main/java/me/zenox/evocraft/abilities/AbilityRegistry.java +++ b/src/main/java/me/zenox/evocraft/abilities/AbilityRegistry.java @@ -1,9 +1,9 @@ package me.zenox.evocraft.abilities; import me.zenox.evocraft.Slot; +import me.zenox.evocraft.abilities.itemabilities.*; import me.zenox.evocraft.util.Util; import org.bukkit.ChatColor; -import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -13,169 +13,265 @@ public class AbilityRegistry { public static final ItemAbility SOUL_RIFT = new ItemAbility(new AbilitySettings() - .setId("soul_rift") + .id("soul_rift") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(100) - .setCooldown(50), ItemAbility::soulRiftAbility); + .manaCost(100) + .cooldown(50), ItemAbility::soulRiftAbility); public static final ItemAbility MAGIC_MISSILE_COMBUST_6 = new ItemAbility(new AbilitySettings() - .setId("magic_missile") + .id("magic_missile") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(0) - .setCooldown(0), + .manaCost(0) + .cooldown(0), (PlayerInteractEvent event, Player p, ItemStack item) -> ItemAbility.magicMissileAbility(event, p, item,true, 6)); public static final ItemAbility MAGIC_MISSILE_DEV = new ItemAbility(new AbilitySettings() - .setId("magic_missile_dev") + .id("magic_missile_dev") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(0) - .setCooldown(0), (PlayerInteractEvent event, Player p, ItemStack item) -> ItemAbility.magicMissileAbility(event, p, item, false, 15)); + .manaCost(0) + .cooldown(0), (PlayerInteractEvent event, Player p, ItemStack item) -> ItemAbility.magicMissileAbility(event, p, item, false, 15)); public static final ItemAbility SMALL_EMBER_SHOOT = new ItemAbility(new AbilitySettings() - .setId("small_ember_shoot") + .id("small_ember_shoot") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(10) - .setCooldown(0), ItemAbility::smallEmberShootAbility); + .manaCost(10) + .cooldown(0), ItemAbility::smallEmberShootAbility); public static final ItemAbility EMBER_SHOOT = new ItemAbility(new AbilitySettings() - .setId("ember_shoot") + .id("ember_shoot") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(50) - .setCooldown(0), ItemAbility::emberShootAbility); + .manaCost(50) + .cooldown(0), ItemAbility::emberShootAbility); public static final ItemAbility CENTRALIZE = new ItemAbility(new AbilitySettings() - .setId("centralize") + .id("centralize") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(150) - .setCooldown(0), (PlayerInteractEvent event, Player p, ItemStack item) -> ItemAbility.centralizeAbility(event, p, item, false, 30)); + .manaCost(150) + .cooldown(0), (PlayerInteractEvent event, Player p, ItemStack item) -> ItemAbility.centralizeAbility(event, p, item, false, 30)); public static final ItemAbility CENTRALIZE_CORRUPT = new ItemAbility(new AbilitySettings()/*"centralize_corrupt", ItemAbility.AbilityAction.RIGHT_CLICK_ALL, 250, 0, (PlayerInteractEvent event, Player p, ItemStack item) -> ItemAbility.centralizeAbility(event, p, item, true, 45)*/ - .setId("centralize_corrupt") + .id("centralize_corrupt") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(250) - .setCooldown(0), (PlayerInteractEvent event, Player p, ItemStack item) -> ItemAbility.centralizeAbility(event, p, item, true, 45)); + .manaCost(250) + .cooldown(0), (PlayerInteractEvent event, Player p, ItemStack item) -> ItemAbility.centralizeAbility(event, p, item, true, 45)); public static final ItemAbility OBSIDIAN_SHARD = new ItemAbility(new AbilitySettings() - .setId("obsidian_shard") + .id("obsidian_shard") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(25) - .setCooldown(0), ItemAbility::obsidianShardAbility); + .manaCost(25) + .cooldown(0), ItemAbility::obsidianShardAbility); public static final ItemAbility TARHELM = new ItemAbility(new AbilitySettings() - .setId("tarhelm") + .id("tarhelm") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(150) - .setCooldown(30), ItemAbility::tarhelmAbility); + .manaCost(150) + .cooldown(30), ItemAbility::tarhelmAbility); public static final AttackAbility JUSTICE = new AttackAbility(new AbilitySettings() - .setId("justice") - .setManaCost(0) - .setCooldown(0) - .setSlot(Slot.MAIN_HAND), AttackAbility::justiceAbility); + .id("justice") + .manaCost(0) + .cooldown(0) + .slot(Slot.MAIN_HAND), AttackAbility::justiceAbility); public static final AttackAbility VERTEX_ABILITY = new AttackAbility(new AbilitySettings() - .setId("vertex_ability") - .setManaCost(20) - .setCooldown(0) - .setSlot(Slot.MAIN_HAND), AttackAbility::vertexAbility); + .id("vertex_ability") + .manaCost(20) + .cooldown(0) + .slot(Slot.MAIN_HAND), AttackAbility::vertexAbility); public static final AttackAbility DARK_FURY = new AttackAbility(new AbilitySettings() - .setId("dark_fury") - .setManaCost(20) - .setCooldown(0) - .setSlot(Slot.MAIN_HAND), AttackAbility::darkFuryAbility); + .id("dark_fury") + .manaCost(20) + .cooldown(0) + .slot(Slot.MAIN_HAND), AttackAbility::darkFuryAbility); public static final FullSetAttackAbility TEST_FULLSET = new FullSetAttackAbility(new AbilitySettings() - .setId("test_fullset") - .setManaCost(10) - .setCooldown(0) - .setSlot(Slot.ARMOR), FullSetAttackAbility::testFullSetAbility); + .id("test_fullset") + .manaCost(10) + .cooldown(0) + .slot(Slot.ARMOR), FullSetAttackAbility::testFullSetAbility); public static final ItemAbility TERRA_STRIKE = new ItemAbility(new AbilitySettings() - .setId("terra_strike") - .setAbilityAction(ItemAbility.AbilityAction.SHIFT_RIGHT_CLICK) - .setManaCost(10) - .setCooldown(5), ItemAbility::terraStrikeAbility); + .id("terra_strike") + .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) + .manaCost(10) + .cooldown(5), ItemAbility::terraStrikeAbility); public static final FullSetAttackAbility ROARING_FLAME = new FullSetAttackAbility(new AbilitySettings() - .setId("roaring_flame") - .setPassive(true) - .setManaCost(0) - .setCooldown(0) - .setSlot(Slot.ARMOR), FullSetAttackAbility::roaringFlameAbility); - public static final MoveAbility LAVA_GLIDER = new MoveAbility(new AbilitySettings() - .setId("lava_glider") - .setPassive(true) - .setManaCost(0) - .setCooldown(0) - .setSlot(Slot.ARMOR), MoveAbility::lavaGliderAbility); + .id("roaring_flame") + .passive(true) + .manaCost(0) + .cooldown(0) + .slot(Slot.ARMOR), FullSetAttackAbility::roaringFlameAbility); public static final ItemAbility DARKCALL = new ItemAbility(new AbilitySettings() - .setId("darkcall") + .id("darkcall") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(0) - .setCooldown(60), ItemAbility::darkcallerAbility); + .manaCost(0) + .cooldown(60), ItemAbility::darkcallerAbility); public static final ItemAbility GILDED_CONSUME = new ItemAbility(new AbilitySettings() - .setId("gilded_consume") + .id("gilded_consume") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(0) - .setCooldown(0), ItemAbility::consumeAbility); + .manaCost(0) + .cooldown(0), ItemAbility::consumeAbility); public static final ItemAbility VOID_WARP = new ItemAbility(new AbilitySettings() - .setId("void_warp") - .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(100) - .setCooldown(1), ItemAbility::voidWarpAbility); - public static final ItemAbility VOIDULAR_RECALL= new ItemAbility(new AbilitySettings() - .setId("voidular_recall") - .setAbilityAction(ItemAbility.AbilityAction.SHIFT_RIGHT_CLICK) - .setManaCost(10) - .setCooldown(1), ItemAbility::voidularRecallAbility); - public static final ItemAbility START_BUTTON = new ItemAbility(new AbilitySettings() - .setId("start_button") - .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(0) - .setCooldown(0), ItemAbility::startButtonAbility); - public static final ItemAbility PORTALIZER = new ItemAbility(new AbilitySettings() - .setId("portalizer") - .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(0) - .setCooldown(0), ItemAbility::portalizerAbility); + .id("void_warp") + .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) + .manaCost(100) + .cooldown(1), ItemAbility::voidWarpAbility); public static final ItemAbility SNOW_SHOT = new ItemAbility(new AbilitySettings() - .setId("snow_shot") + .id("snow_shot") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(5) - .setCooldown(0), ItemAbility::snowShotAbility); + .manaCost(5) + .cooldown(0), ItemAbility::snowShotAbility); public static final FullSetEntityDamagedAbility DIAMANTINE_SHIELD = new FullSetEntityDamagedAbility(new AbilitySettings() - .setId("diamantine_shield") - .setPassive(true) - .setManaCost(0) - .setCooldown(0) - .setSlot(Slot.ARMOR), FullSetEntityDamagedAbility::diamantineShieldAbility); + .id("diamantine_shield") + .passive(true) + .manaCost(0) + .cooldown(0) + .slot(Slot.ARMOR), FullSetEntityDamagedAbility::diamantineShieldAbility); public static final FullSetDamagedAbility GOLEMS_HEART = new FullSetDamagedAbility(new AbilitySettings() - .setId("golems_heart") - .setPassive(true) - .setManaCost(0) - .setCooldown(0) - .setSlot(Slot.ARMOR), FullSetDamagedAbility::golemsHeartAbility, List.of(EntityDamageEvent.DamageCause.ENTITY_EXPLOSION, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION)); + .id("golems_heart") + .passive(true) + .manaCost(0) + .cooldown(0) + .slot(Slot.ARMOR), FullSetDamagedAbility::golemsHeartAbility, List.of(EntityDamageEvent.DamageCause.ENTITY_EXPLOSION, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION)); public static final FullSetDamagedAbility TITANS_HEART = new FullSetDamagedAbility(new AbilitySettings() - .setId("titans_heart") - .setPassive(true) - .setManaCost(0) - .setCooldown(0) - .setSlot(Slot.ARMOR), FullSetDamagedAbility::titansHeartAbility, List.of(EntityDamageEvent.DamageCause.ENTITY_EXPLOSION, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION)); + .id("titans_heart") + .passive(true) + .manaCost(0) + .cooldown(0) + .slot(Slot.ARMOR), FullSetDamagedAbility::titansHeartAbility, List.of(EntityDamageEvent.DamageCause.ENTITY_EXPLOSION, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION)); public static final ItemAbility CRYSTAL_SPIKE = new ItemAbility(new AbilitySettings() - .setId("crystal_spike") + .id("crystal_spike") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(75) - .setCooldown(1), ItemAbility::crystalSpikeAbility); + .manaCost(75) + .cooldown(1), ItemAbility::crystalSpikeAbility); public static final ItemAbility MANA_BOOST = new ItemAbility(new AbilitySettings() - .setId("mana_boost") + .id("mana_boost") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(0) - .setCooldown(0), ItemAbility::manaBoostAbility); + .manaCost(0) + .cooldown(0), ItemAbility::manaBoostAbility); public static final ItemAbility COLOSSAL_SWEEP = new ItemAbility(new AbilitySettings() - .setId("colossal_sweep") + .id("colossal_sweep") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(100) - .setCooldown(0), ItemAbility::colossalSweepAbility); + .manaCost(100) + .cooldown(0), ItemAbility::colossalSweepAbility); public static final ItemAbility THUNDERSTRIKE = new ItemAbility(new AbilitySettings() - .setId("thunderstrike") + .id("thunderstrike") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) - .setManaCost(50) - .setCooldown(0), ItemAbility::thunderstrikeAbility); + .manaCost(50) + .cooldown(0), ItemAbility::thunderstrikeAbility); public static final ItemAbility RAPID_FIRE = new ItemAbility(new AbilitySettings() - .setId("rapid_fire") + .id("rapid_fire") .setAbilityAction(ItemAbility.AbilityAction.RIGHT_CLICK_ALL) , ItemAbility::rapidFireAbility); + // Class Abilities + public static final ClassAbility TELEPORT = new ClassAbility(new AbilitySettings() + .id("mage_teleport") + .manaCost(35) + .cooldown(0) + .range(20) + .strength(1) + .charges(1) + .chargeTime(15) + .modifiers(Modifier.of(Modifier.Type.RANGE, "teleport_range_1", +5), + Modifier.of(Modifier.Type.MANA_COST, "teleport_mana_1", -5), + Modifier.of(Modifier.Type.CHARGE, "teleport_charge_1", +1), + Modifier.of(Modifier.Type.EXECUTABLE, "teleport_dark", ClassAbility::darkTeleport), + Modifier.of(Modifier.Type.STRENGTH, "teleport_strength_1", +1), + Modifier.of(Modifier.Type.CHARGE, "teleport_charge_2", +1), + Modifier.of(Modifier.Type.EXECUTABLE, "teleport_surge", ClassAbility::surgeTeleport), + Modifier.of(Modifier.Type.RANGE, "teleport_range_2", +10), + Modifier.of(Modifier.Type.EXECUTABLE, "teleport_arcane", ClassAbility::arcaneTeleport)) + , ClassAbility::teleportAbility); + + public static final ClassAbility MANA_BALL = new ClassAbility(new AbilitySettings() + .id("mage_mana_ball") + .manaCost(15) + .cooldown(0) + .range(20) + .strength(1) + .charges(-1) + .chargeTime(-1) + .modifiers(Modifier.of(Modifier.Type.MANA_COST, "mana_ball_mana_1", -5), + Modifier.of(Modifier.Type.RANGE, "mana_ball_range_1", +2), + Modifier.of(Modifier.Type.STRENGTH, "mana_ball_strength_1", +1), + Modifier.of(Modifier.Type.EXECUTABLE, "mana_ball_homing", ClassAbility::homingManaBall), + Modifier.of(Modifier.Type.MANA_COST, "mana_ball_strength_2", +1), + Modifier.of(Modifier.Type.RANGE, "mana_ball_range", +5), + Modifier.of(Modifier.Type.EXECUTABLE, "mana_ball_multishot", ClassAbility::multishotManaBall), + Modifier.of(Modifier.Type.MANA_COST, "mana_ball_strength_2", +1), + Modifier.of(Modifier.Type.MULTI, "mana_ball_am", + Modifier.of(Modifier.Type.MANA_COST, "mana_ball_am_mana_boost", +50), + Modifier.of(Modifier.Type.EXECUTABLE, "mana_ball_am_arcane_multishot", ClassAbility::multishotArcaneSingularity), + Modifier.of(Modifier.Type.RANGE, "mana_ball_am_range", +15))) + , ClassAbility::manaBallAbility); + public static final ClassAbility RIFT_BEAM = new ClassAbility(new AbilitySettings() + .id("mage_rift_beam") + .manaCost(40) + .cooldown(0) + .range(20) + .strength(2) + .charges(0) + .chargeTime(0) + .modifiers( + Modifier.of(Modifier.Type.RANGE, "rift_beam_extend", +5), + Modifier.of(Modifier.Type.STRENGTH, "rift_beam_energize", +1), + Modifier.of(Modifier.Type.EXECUTABLE, "rift_beam_mark", ClassAbility::riftBeamMark), + Modifier.of(Modifier.Type.MANA_COST, "rift_beam_efficiency", -10), + Modifier.of(Modifier.Type.EXECUTABLE, "rift_beam_chain", ClassAbility::riftBeamChain), + Modifier.of(Modifier.Type.MULTI, "rift_beam_concentrate", Modifier.of(Modifier.Type.COOLDOWN, "rift_beam_concentrate_cooldown", 0), + Modifier.of(Modifier.Type.MANA_COST, "rift_beam_concentrate_mana_cost", +250)), + Modifier.of(Modifier.Type.EXECUTABLE, "rift_beam_apex", ClassAbility::riftBeamApex) + ), ClassAbility::riftBeamAbility); + public static final ClassAbility RUNE_SHIELD = new ClassAbility(new AbilitySettings() + .id("mage_rune_shield") + .manaCost(50) + .cooldown(30) + .range(0) // Assuming the shield is self-cast and does not have a range. + .strength(1) // This could represent the base level of damage reduction. + .charges(0) + .chargeTime(0) + .modifiers( + Modifier.of(Modifier.Type.RANGE, "rune_shield_duration", +2), // Enhanced Durability + Modifier.of(Modifier.Type.STRENGTH, "rune_shield_barrier", +10), // Reinforced Barrier + Modifier.of(Modifier.Type.MANA_COST, "rune_shield_efficiency", -5), // Mana Efficiency + Modifier.of(Modifier.Type.EXECUTABLE, "rune_shield_illumination", ClassAbility::runeIlluminatingAura), // Illuminating Aura + Modifier.of(Modifier.Type.COOLDOWN, "rune_shield_recovery", -5), // Rapid Recovery + Modifier.of(Modifier.Type.EXECUTABLE, "rune_shield_resonance", ClassAbility::arcaneResonance) // Arcane Resonance + ), ClassAbility::runeShieldAbility); + public static final ClassAbility BLOODLUST = new ClassAbility(new AbilitySettings() + .id("bloodlust") + .manaCost(35) + .cooldown(100) + .strength(1) + .charges(1) + .modifier(Modifier.of(Modifier.Type.EXECUTABLE, "bloodlust_agility", ClassAbility::agilityBloodlust)) + , ClassAbility::bloodlustAbility); + public static final ClassAbility TRIPLE_SLASH = new ClassAbility(new AbilitySettings() + .id("triple_slash") + .manaCost(35) + .cooldown(100) + .strength(1) + .charges(1) + , ClassAbility::tripleSlashAbility); + public static final ClassAbility BULL_RUSH = new ClassAbility(new AbilitySettings() + .id("bull_rush") + .manaCost(35) + .cooldown(100) + .strength(1) + .charges(1) + , ClassAbility::bullRushAbility); + public static final ClassAbility COUNTERSTRIKE = new ClassAbility(new AbilitySettings() + .id("counterstrike") + .manaCost(15) + .cooldown(5) + .strength(10) + .charges(3) + , ClassAbility::counterstrikeAbility); + +// public static final ClassAbility PRECISION_SHOT = new ClassAbility(new AbilitySettings() +// .id("precision_shot") +// .manaCost(15) +// .cooldown(5) +// .strength(10) +// .charges(3) +// .modifiers( +// Modifier.of(Modifier.Type.RANGE, "precision_shot_range", +20), +// Modifier.of(Modifier.Type.MANA_COST, "precision_cheaper_1", -20) +// ) +// , ClassAbility::precisionShotAbility); + public static void registerAbilities(){ - Util.logToConsole("Registering %s abilities.".formatted(ChatColor.GOLD + "" + Ability.registeredAbilities.size() + "" + ChatColor.RESET)); + Util.logToConsole("Registering %s abilities.".formatted(ChatColor.GOLD + "" + Ability.registeredAbilities.size() + ChatColor.RESET)); } } diff --git a/src/main/java/me/zenox/evocraft/abilities/AbilitySettings.java b/src/main/java/me/zenox/evocraft/abilities/AbilitySettings.java index 1c43ec6..0f9c718 100644 --- a/src/main/java/me/zenox/evocraft/abilities/AbilitySettings.java +++ b/src/main/java/me/zenox/evocraft/abilities/AbilitySettings.java @@ -1,7 +1,10 @@ package me.zenox.evocraft.abilities; import me.zenox.evocraft.Slot; +import me.zenox.evocraft.abilities.itemabilities.ItemAbility; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; /** @@ -13,9 +16,14 @@ public class AbilitySettings { private double cooldown; private Slot slot; private boolean isPassive; + private List modifiers; // Ability-Specific Settings private ItemAbility.AbilityAction abilityAction; + private int strength; + private int charges; + private int range; + private int chargeTime; public AbilitySettings() { this.id = "default" + UUID.randomUUID(); @@ -24,13 +32,18 @@ public AbilitySettings() { this.slot = Slot.EITHER_HAND; this.isPassive = false; this.abilityAction = ItemAbility.AbilityAction.NONE; + this.modifiers = new ArrayList<>(); + this.strength = 0; + this.charges = 0; + this.range = 0; + this.chargeTime = 0; } public String getId() { return id; } - public AbilitySettings setId(String id) { + public AbilitySettings id(String id) { this.id = id; return this; } @@ -39,7 +52,7 @@ public int getManaCost() { return manaCost; } - public AbilitySettings setManaCost(int manaCost) { + public AbilitySettings manaCost(int manaCost) { this.manaCost = manaCost; return this; } @@ -48,7 +61,7 @@ public double getCooldown() { return cooldown; } - public AbilitySettings setCooldown(double cooldown) { + public AbilitySettings cooldown(double cooldown) { this.cooldown = cooldown; return this; } @@ -57,7 +70,7 @@ public Slot getSlot() { return slot; } - public AbilitySettings setSlot(Slot slot) { + public AbilitySettings slot(Slot slot) { this.slot = slot; return this; } @@ -66,7 +79,7 @@ public boolean isPassive() { return isPassive; } - public AbilitySettings setPassive(boolean passive) { + public AbilitySettings passive(boolean passive) { isPassive = passive; return this; } @@ -79,4 +92,64 @@ public AbilitySettings setAbilityAction(ItemAbility.AbilityAction abilityAction) this.abilityAction = abilityAction; return this; } + + public List getModifiers() { + return modifiers; + } + + public AbilitySettings modifiers(List modifiers) { + this.modifiers = modifiers; + return this; + } + + public AbilitySettings modifiers(Modifier... modifiers) { + this.modifiers.addAll(List.of(modifiers)); + return this; + } + + public AbilitySettings modifier(Modifier modifier) { + this.modifiers.add(modifier); + return this; + } + + public int getStrength() { + return strength; + } + + public AbilitySettings strength(int strength) { + this.strength = strength; + return this; + } + + public int getCharges() { + return charges; + } + + public AbilitySettings charges(int charges) { + this.charges = charges; + return this; + } + + public int getRange() { + return range; + } + + public AbilitySettings range(int range) { + this.range = range; + return this; + } + + public int getChargeTime() { + return chargeTime; + } + + /** + * Sets the charge time of the ability + * @param chargeTime Charge time in seconds + * @return The ability settings + */ + public AbilitySettings chargeTime(int chargeTime) { + this.chargeTime = chargeTime; + return this; + } } diff --git a/src/main/java/me/zenox/evocraft/abilities/ClassAbility.java b/src/main/java/me/zenox/evocraft/abilities/ClassAbility.java new file mode 100644 index 0000000..3cc4e8b --- /dev/null +++ b/src/main/java/me/zenox/evocraft/abilities/ClassAbility.java @@ -0,0 +1,1091 @@ +package me.zenox.evocraft.abilities; + +import com.ticxo.modelengine.api.ModelEngineAPI; +import com.ticxo.modelengine.api.model.ActiveModel; +import com.ticxo.modelengine.api.model.ModeledEntity; +import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.data.PlayerData; +import me.zenox.evocraft.data.PlayerDataManager; +import me.zenox.evocraft.util.GeometryUtils; +import me.zenox.evocraft.util.TriConsumer; +import me.zenox.evocraft.util.Util; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.*; +import org.bukkit.entity.*; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Consumer; + +public class ClassAbility extends Ability { + final List modifiers; + + @SaveState + protected TriConsumer executable; + + @SaveState + private int strength; + @SaveState + private int charges; + @SaveState + private int chargeTime; + @SaveState + private int range; + + private final Map baseState; + private boolean modified = false; + + public ClassAbility(AbilitySettings settings, TriConsumer executable) { + super(settings.getId(), settings.getManaCost(), settings.getCooldown(), settings.isPassive()); + this.executable = executable; + this.modifiers = settings.getModifiers(); + + // stats + this.strength = settings.getStrength(); + this.charges = settings.getCharges(); + this.chargeTime = settings.getChargeTime(); + this.range = settings.getRange(); + + // save basestate snapshot + this.baseState = getState(); + } + + public Map getState(){ + Map map = new HashMap<>(); + for (Class clazz = this.getClass(); clazz != null; clazz = clazz.getSuperclass()){ + for (Field f : clazz.getDeclaredFields()){ + if (f.isAnnotationPresent(SaveState.class)){ + try { + f.setAccessible(true); + map.put(f.getName(), f.get(this)); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + } + return map; + } + + @Override + public void useAbility(Event event) { + try { + PlayerInteractEvent e = (PlayerInteractEvent) event; + Player p = e.getPlayer(); + + PlayerData data = PlayerDataManager.getInstance().getPlayerData(p.getUniqueId()); + + int level = data.getPathLevel(data.getPlayerClass().tree().path(this)); + if (level == -1) { + Util.sendActionBar(p, "&c&l%s LOCKED!".formatted(this.getDisplayName().toUpperCase())); + return; // ability is not unlocked + } + + Util.sendMessage(p, "&aUsing ability %s at level %d".formatted(this.getId(), level)); + + applyModifiers(level); // apply modifiers to the ability + + // Check if ability is on cooldown + if (isAbilityOnCooldown(p)) { + sendCooldownMessage(p); + return; + } + + if (this.getCharges() > 0 && noCharges(p)) { + sendNoChargesMessage(p); + return; + } + + if (notEnoughMana(p, this.getManaCost())) { + sendManaInsufficientMessage(p); + return; + } + + deductMana(p, this.getManaCost()); + + String chargeMsg = ""; + if (this.getCharges() > 0) { + int chargesLeft = Ability.cooldownManager.consumeCharge(p, this); + chargeMsg = " &6(&e%d&6/%d) (-1)".formatted(chargesLeft, this.getCharges()); + } + showMessage(p, chargeMsg); + + this.executable.accept(e, p, this); + setAbilityCooldown(p); + } finally { + reset(); + } + + } + + protected boolean noCharges(Player p) { + return cooldownManager.isOnCooldown(p, this); + } + + protected void sendNoChargesMessage(Player p) { + Util.sendActionBar(p, "&c&lNO CHARGES LEFT"); + } + + + + /** + * Execute a code block with the context of the ability's modifiers applied + * @param level the level of the ability + * @param code the code to execute + */ + public void executeWithLevel(int level, @NotNull Consumer code){ + applyModifiers(level); + try { + code.accept(this); + } finally { + reset(); + } + } + + /** + * Execute a code block with the context of the ability's modifiers applied + * @param p the player to fetch the level from + * @param code the code to execute + */ + public void executeAsPlayer(@NotNull Player p, Consumer code){ + PlayerData data = PlayerDataManager.getInstance().getPlayerData(p.getUniqueId()); + int level = data.getPathLevel(data.getPlayerClass().tree().path(this)); + executeWithLevel(level, code); + } + + public void applyModifiers(int level){ + if (modified) throw new IllegalStateException("You may not modify the ability while it is already being modified."); + for(int i = 0; i < level; i++){ + modifiers.get(i).modify(this); + } + modified = true; + } + + // Recreate the ability to its original state + public void reset(){ + for (Class clazz = this.getClass(); clazz != null; clazz = clazz.getSuperclass()) { + for (Field f : clazz.getDeclaredFields()) { + if (f.isAnnotationPresent(SaveState.class)) { + try { + f.setAccessible(true); + f.set(this, baseState.get(f.getName())); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + } + modified = false; + } + + public List getModifiers() { + return modifiers; + } + + public int getStrength() { + return strength; + } + + public void setStrength(int strength) { + this.strength = strength; + } + + public int getCharges() { + return charges; + } + + public void setCharges(int charges) { + this.charges = charges; + } + + public int getChargeTime() { + return chargeTime; + } + + public ClassAbility setChargeTime(int chargeTime) { + this.chargeTime = chargeTime; + return this; + } + + public int getRange() { + return range; + } + + public void setRange(int range) { + this.range = range; + } + + public TriConsumer getExecutable() { + return this.executable; + } + + public void setExecutable(TriConsumer executable) { + this.executable = executable; + } + + /* + * Ability Executables + */ + private static void teleport(Player player, int distance) { + Location currentLocation = player.getLocation(); + Vector direction = currentLocation.getDirection().normalize(); + + // This will check each block along the path, up to the distance + for (int i = 1; i <= distance; i++) { + Location targetLocation = currentLocation.clone().add(direction.clone().multiply(1)); // Move 1 block at a time in the direction + // Check for solid blocks at the player's feet or head level + if (targetLocation.getBlock().getType().isSolid() || targetLocation.clone().add(0, 1, 0).getBlock().getType().isSolid()) { + // If a solid block is found, stop and teleport the player to the last safe location + break; + } + // Update currentLocation to the last checked location + currentLocation = targetLocation; + } + + // Perform the actual teleportation + player.teleport(currentLocation.add(0, 0.1, 0)); // Slightly raise the Y value to prevent suffocation + } + + private static void teleportEffect(Location startLoc, Location endLoc, Color color, Player player, int damage, double width) { + List tracedPath = GeometryUtils.lerpEdges(List.of(startLoc.toVector(), endLoc.toVector()), (int) (1.3 * startLoc.distance(endLoc))); + Vector direction = endLoc.toVector().subtract(startLoc.toVector()).normalize(); + + new BukkitRunnable() { + int a = 0; + @Override + public void run() { + if (a >= tracedPath.size()/2) { + cancel(); + return; + } + + Location currentLoc = tracedPath.get(a).toLocation(player.getWorld()); + Vector perpendicular = new Vector(-direction.getZ(), 0, direction.getX()).normalize().multiply(width / 2); + + for (double i = -width / 2; i <= width / 2; i += width / 10) { + Location effectLoc = currentLoc.clone().add(perpendicular.clone().multiply(i)); + player.getWorld().getNearbyEntities(effectLoc, 0.5, 0.5, 0.5).forEach(entity -> { + if (entity instanceof Damageable && !entity.equals(player)) { + ((Damageable) entity).damage(damage); + } + }); + player.getWorld().spawnParticle(Particle.REDSTONE, effectLoc, 1, 0.1, 0, 0.1, new Particle.DustOptions(color, 1)); + } + + a++; + } + }.runTaskTimer(EvoCraft.getPlugin(), 0, 1); + } + + + public static void teleportAbility(PlayerInteractEvent event, Player player, ClassAbility ability) { + Location prev = player.getLocation(); + teleport(player, ability.getRange()); + + // Create particles along the path + teleportEffect(prev, player.getLocation(), Color.fromRGB(0, 123, 255), player, 0, 1); + } + + /** + * Dark Teleport Executable that damages entities along the path + */ + public static void darkTeleport(PlayerInteractEvent event, Player player, ClassAbility ability) { + Location prev = player.getLocation(); + + // Teleport the player using the helper method + teleport(player, ability.getRange()); + + // Create particles along the path and damage entities using the helper method + teleportEffect(prev, player.getLocation(), org.bukkit.Color.fromRGB(0, 12, 89), player, 5 * ability.getStrength(), 1); + } + + + public static void surgeTeleport(PlayerInteractEvent event, Player player, ClassAbility ability) { + Location prev = player.getLocation(); + + teleport(player, ability.getRange()); + + teleportEffect(prev, player.getLocation(), org.bukkit.Color.fromRGB(102, 0, 126), player, 10 * ability.getStrength(), 2); + + } + + public static void arcaneTeleport(PlayerInteractEvent event, Player player, ClassAbility ability) { + + darkTeleport(event, player, ability); + } + + // Constants for the homing behavior + private static final double ACCELERATION_RATE = 0.2; + private static final double MAX_TURN_RATE = Math.toRadians(7); + + public static void manaBallAbility(PlayerInteractEvent event, Player player, ClassAbility ability) { + Snowball projectile = createProjectile(player, ability); + startParticleTask(player, projectile, ability.getRange()).runTaskTimer(EvoCraft.getPlugin(), 0, 2); + } + + public static void homingManaBall(PlayerInteractEvent event, Player player, ClassAbility ability) { + Snowball projectile = createProjectile(player, ability); + startHomingTask(player, projectile, ability.getRange(), false).runTaskTimer(EvoCraft.getPlugin(), 0, 2); + } + + public static void multishotManaBall(PlayerInteractEvent event, Player player, ClassAbility ability) { + // Here you can define how many projectiles you want to shoot + int numberOfProjectiles = 3; + for (int i = 0; i < numberOfProjectiles; i++) { + Snowball projectile = createProjectile(player, ability); + // Let's keep the projectiles straight but instead shoot them in parallel with offsets + Vector direction = projectile.getLocation().getDirection().setY(0).normalize(); + Vector perpendicular = direction.rotateAroundY(Math.toRadians(90)); + Vector offset = perpendicular.multiply(((i - numberOfProjectiles/2)*1.5)); + projectile.teleport(projectile.getLocation().add(offset)); + startHomingTask(player, projectile, ability.getRange(), false).runTaskTimer(EvoCraft.getPlugin(), 0, 2); + } + } + + private static Snowball createProjectile(Player player, ClassAbility ability) { + Snowball projectile = player.launchProjectile(Snowball.class); + projectile.setGravity(false); + projectile.setVelocity(player.getLocation().getDirection().multiply(1.5)); + projectile.setMetadata("mana_projectile", new FixedMetadataValue(EvoCraft.getPlugin(), ability.getStrength())); + return projectile; + } + + private static BukkitRunnable startParticleTask(Player player, Snowball projectile, int range) { + return new BukkitRunnable() { + final Location start = player.getLocation().clone(); + @Override + public void run() { + if (start.distance(projectile.getLocation()) > range || !projectile.isValid()) { + projectile.remove(); + cancel(); + return; + } + spawnParticles(projectile.getLocation()); + } + }; + } + + private static BukkitRunnable startHomingTask(Player player, Snowball projectile, int range, boolean down) { + return new BukkitRunnable() { + final Location start = player.getLocation().clone(); + @Override + public void run() { + if (start.distance(projectile.getLocation()) > range || !projectile.isValid()) { + projectile.remove(); + cancel(); + return; + } + LivingEntity target = findNearestTarget(projectile, player); + if (target != null) { + adjustProjectileVelocity(projectile, target, down); + } + spawnParticles(projectile.getLocation()); + } + }; + } + + private static void spawnParticles(Location location) { + location.getWorld().spawnParticle(Particle.END_ROD, location, 1, 0.1, 0, 0.1, 0); + location.getWorld().spawnParticle(Particle.REDSTONE, location, 1, 0, 0.1, 0, + new Particle.DustOptions(Color.fromRGB(0, 255, 255), 1)); + } + + private static void adjustProjectileVelocity(Snowball projectile, LivingEntity target, boolean downwards) { + Vector currentVelocity = projectile.getVelocity(); + Vector targetDirection = target.getEyeLocation().toVector().subtract(projectile.getLocation().toVector()); + double currentHorizontalSpeed = Math.sqrt(currentVelocity.getX() * currentVelocity.getX() + currentVelocity.getZ() * currentVelocity.getZ()); + + Vector velocityAdjustment = targetDirection.clone().subtract(currentVelocity).normalize(); + Vector adjustedVelocity = currentVelocity.clone().add(velocityAdjustment); + + if (downwards) { + // Keep the horizontal velocity components the same to maintain horizontal speed + double adjustedY = adjustedVelocity.getY() - ACCELERATION_RATE * 1.1; // Slightly increase the downward acceleration + adjustedVelocity = new Vector(currentVelocity.getX(), adjustedY, currentVelocity.getZ()); + } else { + if (currentVelocity.angle(adjustedVelocity) > MAX_TURN_RATE) { + adjustedVelocity = rotateVectorTowards(currentVelocity, targetDirection.normalize(), MAX_TURN_RATE); + } + adjustedVelocity = adjustedVelocity.normalize().multiply(currentHorizontalSpeed).setY(adjustedVelocity.getY()); + } + + projectile.setVelocity(adjustedVelocity); + } + + + private static Vector rotateVectorTowards(Vector source, Vector target, double maxAngle) { + double angle = source.angle(target); + if (angle < maxAngle) return target; // No need to rotate if within max angle + + double theta = Math.min(angle, maxAngle) / angle; + return source.clone().multiply(1 - theta).add(target.clone().multiply(theta)).normalize(); + } + + private static LivingEntity findNearestTarget(Entity projectile, Player caster) { + Location location = projectile.getLocation(); + double minDistance = Double.MAX_VALUE; + LivingEntity nearest = null; + + for (Entity entity : location.getWorld().getNearbyEntities(location, 10, 20, 10) + .stream() + .filter(entity -> entity instanceof LivingEntity && ((LivingEntity) entity).hasLineOfSight(projectile)).toList()) { + if (entity instanceof LivingEntity && !entity.equals(caster)) { + double distance = entity.getLocation().distance(location); + if (distance < minDistance) { + minDistance = distance; + nearest = (LivingEntity) entity; + } + } + } + return nearest; + } + + public static void manaBallDamage(@NotNull ProjectileHitEvent event, int strength){ + // Logic to deal damage + if (event.getHitEntity() instanceof LivingEntity) { + LivingEntity target = (LivingEntity) event.getHitEntity(); + target.damage(5.0*strength, (Entity) event.getEntity().getShooter()); // Deal 5 points of damage, customize as needed + target.setNoDamageTicks(0); + target.setFreezeTicks(target.getFreezeTicks()+strength*20); + } + // Remove the projectile upon impact + event.getEntity().remove(); + } + + public static void multishotArcaneSingularity(PlayerInteractEvent event, Player player, ClassAbility ability) { + int numberOfProjectiles = 3; + double spreadAngle = 15; // Angle between each projectile + + Vector baseDirection = player.getLocation().getDirection().normalize(); + double basePitch = baseDirection.getY(); // Store the original pitch + + for (int i = 0; i < numberOfProjectiles; i++) { + // Calculate the yaw offset by spreading the projectiles evenly + double yawOffsetDegrees = spreadAngle * (i - (numberOfProjectiles - 1) / 2.0); + Vector direction = rotateVectorAroundY(baseDirection.setY(0).normalize(), yawOffsetDegrees); + direction.setY(basePitch); // Set the original pitch back to the direction vector + direction.normalize(); // Normalize the vector after adjusting pitch + + Snowball projectile = player.launchProjectile(Snowball.class); + projectile.setVelocity(direction.multiply(3.0)); + projectile.setMetadata("arcane_singularity", new FixedMetadataValue(EvoCraft.getPlugin(), true)); + Location prev = projectile.getLocation().clone(); + + new BukkitRunnable() { + final int abilityRange = ability.getRange(); + @Override + public void run() { + if (projectile.isDead() || projectile.isOnGround() || reachMaxRange(projectile, prev, abilityRange)) { + createSingularity(projectile.getLocation(), ability, player); + this.cancel(); // Stop the task after the singularity has been created + } + spawnParticles(projectile.getLocation()); + } + }.runTaskTimer(EvoCraft.getPlugin(), 0L, 1L); + + startHomingTask(player, projectile, ability.getRange(), true).runTaskTimer(EvoCraft.getPlugin(), 0, 2); + } + } + + private static Vector rotateVectorAroundY(Vector vector, double angleDegrees) { + double angleRadians = Math.toRadians(angleDegrees); + double cos = Math.cos(angleRadians); + double sin = Math.sin(angleRadians); + double x = vector.getX() * cos + vector.getZ() * sin; + double z = vector.getX() * -sin + vector.getZ() * cos; + return new Vector(x, vector.getY(), z); + } + + private static boolean reachMaxRange(Projectile projectile, Location initial, int range) { + return projectile.getLocation().distance(initial) >= range; + } + + private static void createSingularity(Location location, ClassAbility ability, Player player) { + // Create a singularity effect at the location + int range = ability.getRange()/3; + int duration = ability.getRange()*20/3; + spawnSingularityParticles(location, duration, range); + applySingularityEffects(location, duration, range, player); + + // Schedule to end the singularity effect after its lifetime + Bukkit.getScheduler().runTaskLater(EvoCraft.getPlugin(), () -> { + endSingularity(location, ability); + }, duration); // Duration based on ability settings + } + + private static void spawnSingularityParticles(Location loc, int duration, int range) { + // Spawn particles to indicate the singularity + // Placeholder for actual particle effect code + final double RADIUS = range; + final double DELTA_ANGLE = Math.PI / 16; + + Location location = loc.clone().add(0, 1, 0).setDirection(new Vector(0, 0, 0)); + new BukkitRunnable(){ + double angle = 0; + int a = 0; + @Override + public void run(){ + if (a > duration) { + cancel(); + return; + } + spawnParticles(location.clone().add(Math.cos(angle) * RADIUS, 0, Math.sin(angle) * RADIUS)); + spawnParticles(location.clone().add(Math.cos(angle + Math.PI) * RADIUS, 0, Math.sin(angle + Math.PI) * RADIUS)); + spawnParticles(location.clone().add(0, RADIUS + Math.sin(angle) * RADIUS / 2, 0)); + angle += DELTA_ANGLE; + + if (angle % (Math.PI / 2) < DELTA_ANGLE) + location.getWorld().playSound(location.clone().add(0, RADIUS + Math.sin(angle) * RADIUS / 2, 0), Sound.ENTITY_FIREWORK_ROCKET_TWINKLE, 1, 0); + a++; + } + }.runTaskTimer(EvoCraft.getPlugin(), 0L, 1L); + } + + + private static void applySingularityEffects(Location location, int duration, int range, Player p) { + final int radius = range; + final double pullStrength = 0.2; // Example pull strength + final double gravityEffect = 0.3; // Example additional gravity effect + + new BukkitRunnable() { + int a = 0; + @Override + public void run() { + if (a > duration) { + cancel(); + return; + } + location.getWorld().getNearbyEntities(location, radius, radius, radius).forEach(entity -> { + if (entity instanceof LivingEntity livingEntity && !entity.equals(p)) { + double distance = location.distance(livingEntity.getLocation()); + + // Apply slowness effect + int effectStrength = (int) (distance / radius * 4); // Scale from 0 to 4 + if (effectStrength > 0) { + livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 10, effectStrength, false, false, false)); + } + + livingEntity.setFreezeTicks(livingEntity.getFreezeTicks()+15); + + // Apply a grounding effect + if (livingEntity.isOnGround()) { + // Player is on the ground, possibly apply a minor pull + if (distance > radius) { + Vector towardsCenter = location.toVector().subtract(livingEntity.getLocation().toVector()).normalize(); + livingEntity.setVelocity(towardsCenter.multiply(pullStrength)); + } + } else { + // Player is in the air, apply downward force to simulate increased gravity + Vector currentVelocity = livingEntity.getVelocity(); + livingEntity.setVelocity(new Vector(currentVelocity.getX(), + Math.max(-gravityEffect, currentVelocity.getY() - gravityEffect), + currentVelocity.getZ())); + } + } + }); + a+= 5; + } + }.runTaskTimer(EvoCraft.getPlugin(), 0L, 5L); // Repeat every second + } + + + private static void endSingularity(Location location, ClassAbility ability) { + // Logic to remove the singularity effects and clean up + // For example, removing potion effects from players in the area + location.getWorld().getNearbyEntities(location, ability.getRange(), ability.getRange(), ability.getRange()) + .stream() + .filter(entity -> entity instanceof Player) + .map(entity -> (Player) entity) + .forEach(player -> player.removePotionEffect(PotionEffectType.SLOW)); + } + + /** + * Casts the base Rift Beam ability. + * The beam damages and pierces through enemies in a straight line from the player's position. + * + * @param event The player interaction event. + * @param player The player casting the ability. + * @param ability The class ability information. + */ + public static void riftBeamAbility(PlayerInteractEvent event, Player player, ClassAbility ability) { + // 1. Calculate the beam trajectory from the player's eye location in the direction they are looking. + Location start = player.getEyeLocation(); + Location end = player.getEyeLocation().add(player.getEyeLocation().getDirection().multiply(ability.getRange())); + // 2. Spawn particles along this line to simulate the beam effect. + // 3. Check for entities in the beam's path and apply damage to them. + alongPath(start, end, location -> { + location.getWorld().spawnParticle(Particle.END_ROD, location, 1, 0.1, 0, 0.1, 0); + player.getWorld().spawnParticle(Particle.REDSTONE, location, 2, 0, 0, 0, + new Particle.DustOptions(Color.fromRGB(144, 0, 255), 1)); + player.getWorld().getNearbyEntities(location, 0.5, 0.5, 0.5).forEach(entity -> { + if (entity instanceof Damageable && !entity.equals(player)) { + ((Damageable) entity).damage(ability.getStrength()*5); + } + }); + }); + } + + private static void alongPath(Location start, Location end, Consumer loc){ + List tracedPath = GeometryUtils.lerpEdges(List.of(start.toVector(), end.toVector()), (int) (1.3 * start.distance(end))); + tracedPath = tracedPath.subList(0, tracedPath.size()/2); + tracedPath.forEach(vector -> { + loc.accept(vector.toLocation(start.getWorld())); + }); + } + + /** + * Applies a mark to enemies hit by the Rift Beam. + * Marked enemies take increased damage from all sources for a short duration. + * + * @param event The player interaction event. + * @param player The player casting the ability. + * @param ability The class ability information. + */ + public static void riftBeamMark(PlayerInteractEvent event, Player player, ClassAbility ability) { + + Location start = player.getEyeLocation(); + Location end = player.getEyeLocation().add(player.getEyeLocation().getDirection().multiply(ability.getRange())); + // Spawn particles along this line to simulate the beam effect. + // Check for entities in the beam's path and apply damage to them. + alongPath(start, end, location -> { + location.getWorld().spawnParticle(Particle.END_ROD, location, 1, 0.1, 0, 0.1, 0); + player.getWorld().spawnParticle(Particle.REDSTONE, location, 2, 0, 0, 0, + new Particle.DustOptions(Color.fromRGB(144, 0, 255), 1)); + player.getWorld().getNearbyEntities(location, 0.5, 0.5, 0.5).forEach(entity -> { + if (entity instanceof LivingEntity lEntity && !entity.equals(player)) { + lEntity.damage(ability.getStrength()*5); + + // Apply a potion effect to the target + lEntity.addPotionEffect(new PotionEffect(PotionEffectType.GLOWING, 20*ability.getStrength(), 0)); + + } + }); + }); + } + + /** + * Chains the Rift Beam to additional nearby enemies after hitting the initial target. + * + * @param event The player interaction event. + * @param player The player casting the ability. + * @param ability The class ability information. + */ + public static void riftBeamChain(PlayerInteractEvent event, Player player, ClassAbility ability) { + double distance = ability.getRange(); + Set explored = new HashSet<>(); + + Location start = player.getEyeLocation(); + Vector direction = start.getDirection().normalize(); + + Optional hitEntity = findFirstEntity(start, direction, distance, player); + + if (hitEntity.isPresent()) { + LivingEntity target = hitEntity.get(); + target.damage(ability.getStrength() * 5); + explored.add(target); + createParticlePath(start, target.getLocation(), player); + new BukkitRunnable() { + @Override + public void run() { + chainToClosestEntities(target, player, ability, explored, distance, 1); + } + }.runTaskLater(EvoCraft.getPlugin(), 5L); + + // create visual particle path to show that it was casted, but nothing was hit + } else { + Location end = findBeamHitLocation(start, direction, distance); + createParticlePath(start, findBeamHitLocation(start, direction, distance), player); + end.getWorld().spawnParticle(Particle.REDSTONE, end, 10, 0.2, 0.2, 0.2, + new Particle.DustOptions(Color.fromRGB(144, 0, 255), 1)); + end.getWorld().spawnParticle(Particle.END_ROD, end, 10, 0.2, 0.2, 0.2); + } + + } + + private static Optional findFirstEntity(Location start, Vector direction, double distance, Player player) { + double stepSize = 0.5; + Vector stepVector = direction.clone().normalize().multiply(stepSize); + + for (double i = 0; i <= distance; i += stepSize) { + Location currentLoc = start.clone().add(stepVector.clone().multiply(i)); + + // Check if a block is hit + if (currentLoc.getBlock().getType() != Material.AIR) { + return Optional.empty(); + } + + List nearbyEntities = (List) currentLoc.getNearbyLivingEntities(1); + for (LivingEntity entity : nearbyEntities) { + if (!entity.equals(player)) { + return Optional.of(entity); + } + } + } + return Optional.empty(); + } + + private static Location findBeamHitLocation(Location start, Vector direction, double distance) { + double stepSize = 0.5; + Vector stepVector = direction.clone().normalize().multiply(stepSize); + Location currentLoc = start.clone(); + + for (double i = 0; i <= distance; i += stepSize) { + currentLoc.add(stepVector); + if (currentLoc.getBlock().getType() != Material.AIR) { + return currentLoc; + } + } + return start.clone().add(direction.multiply(distance)); + } + + private static void chainToClosestEntities(LivingEntity initialTarget, Player player, ClassAbility ability, Set explored, double remainingDistance, double damageMultiplier) { + + double closestDistanceSquared = Double.MAX_VALUE; + LivingEntity closestEntity = null; + + + // Find the closest entity within the remaining distance + for (LivingEntity entity : initialTarget.getLocation().getWorld().getNearbyLivingEntities(initialTarget.getLocation(), remainingDistance)) { + if (!entity.equals(player) && !explored.contains(entity)) { + double distanceSquared = entity.getLocation().distanceSquared(initialTarget.getLocation()); + if (distanceSquared < closestDistanceSquared) { + closestDistanceSquared = distanceSquared; + closestEntity = entity; + } + } + } + + // If a valid closest entity is found + if (closestEntity != null && initialTarget.hasLineOfSight(closestEntity)) { + // Apply reduced damage to the closest entity + closestEntity.damage(ability.getStrength() * 5 * damageMultiplier); + explored.add(closestEntity); + + // Create particle effects from the last target to the new one + createParticlePath(initialTarget.getEyeLocation(), closestEntity.getEyeLocation(), player); + final LivingEntity finalClosestEntity = closestEntity; + + // Calculate remaining distance and continue chaining if possible + double distanceToNextTarget = Math.sqrt(closestDistanceSquared); + if (remainingDistance - distanceToNextTarget > 0) { + new BukkitRunnable() { + @Override + public void run() { + chainToClosestEntities(finalClosestEntity, player, ability, explored, remainingDistance - distanceToNextTarget, damageMultiplier * 0.8); // reduce damage by 10% each chain + } + }.runTaskLater(EvoCraft.getPlugin(), 5L); + } + } + + new BukkitRunnable() { + @Override + public void run() { + } + }.runTaskLater(EvoCraft.getPlugin(), 5L); // 20L represents a delay of 1 second (20 ticks) + } + + private static void createParticlePath(Location start, Location end, Player player) { + alongPath(start, end, location -> { + + location.getWorld().spawnParticle(Particle.END_ROD, location, 1, 0.1, 0, 0.1, 0); + location.getWorld().spawnParticle(Particle.REDSTONE, location, 2, 0, 0, 0, + new Particle.DustOptions(Color.fromRGB(144, 0, 255), 1)); + }); + } + + /** + * The ultimate upgrade of the Rift Beam ability. + * Charges up to unleash a devastating blast with one main beam. + * + * @param event The player interaction event. + * @param player The player casting the ability. + * @param ability The class ability information. + */ + public static void riftBeamApex(PlayerInteractEvent event, Player player, ClassAbility ability) { + // Start charging + startCharge(player); + + // Schedule task to check for charge completion + new BukkitRunnable() { + @Override + public void run() { + if (isFullyCharged(player)) { + // On full charge, release the beams + releaseMainBeam(player, ability); + + this.cancel(); // Stop the task + } + } + }.runTaskTimer(EvoCraft.getPlugin(), 0L, 1L); // Check every tick + } + + public static void startCharge(Player player) { + // Display charging particles or effects around the player. + player.getWorld().spawnParticle(Particle.END_ROD, player.getLocation(), 10, 0.5, 0.5, 0.5, 0); + // Record the start time of the charge. + player.setMetadata("charge_start_time", new FixedMetadataValue(EvoCraft.getPlugin(), System.currentTimeMillis())); + + // Start a task that increases the pitch of the sound and sends a message to the action bar as the charge progresses + new BukkitRunnable() { + @Override + public void run() { + + long chargeStartTime = player.getMetadata("charge_start_time").get(0).asLong(); + long elapsedTime = System.currentTimeMillis() - chargeStartTime; + if (elapsedTime < 5000) { + // Calculate the percentage of the elapsed time relative to the total charge time + float percentage = (float) elapsedTime / 5000; // Assuming 5 seconds as the total charge time + + // Calculate the pitch based on the percentage + float pitch = 0.5f + 0.5f * percentage; // Assuming the pitch ranges from 0.5 to 1.0 + + // Play the sound with the calculated pitch + if ((int) (percentage * 100) % 10 == 0) player.playSound(player.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 1.0f, pitch); + + // Summon particle effects to look like the player is drawing power from the ground + // particles should move from the ground towards the player + Location loc = player.getLocation().clone().add(0, 0.5, 0); + Vector direction = loc.toVector().subtract(player.getLocation().toVector()).normalize(); + Vector perpendicular = direction.clone().rotateAroundY(Math.toRadians(90)); + Vector offset = perpendicular.multiply(0.5); + loc.add(offset); + player.getWorld().spawnParticle(Particle.END_ROD, loc, 1, 0.1, 0.1, 0.1, 0); + + // Send a message to the action bar with the calculated percentage + Component message = Component.text("Charging... ", NamedTextColor.GREEN) + .append(Component.text(Math.round(percentage * 100) + "%")); + + Util.sendActionBar(player, message); + } else { + // Stop the task when the charge is complete + this.cancel(); + } + } + }.runTaskTimer(EvoCraft.getPlugin(), 0L, 5L); + } + + public static boolean isFullyCharged(Player player) { + // Check if the required charge time has elapsed. + long chargeStartTime = player.getMetadata("charge_start_time").get(0).asLong(); + long chargeDuration = System.currentTimeMillis() - chargeStartTime; + // Return true if fully charged, false otherwise. + return chargeDuration >= 5000; // Assuming 5 seconds as the required charge time + } + + public static void releaseMainBeam(Player player, ClassAbility ability) { + // Create and launch the main beam. + Location start = player.getEyeLocation(); + Location end = player.getEyeLocation().add(player.getEyeLocation().getDirection().multiply(ability.getRange() * 2)); // Assuming the main beam has twice the range + double totalDistance = start.distance(end); + + new BukkitRunnable() { + int ticks = 0; // Count the number of ticks + @Override + public void run() { + if (ticks < 20) { // Run for 20 ticks (1 second) + double currentDistance = totalDistance * (ticks / 20.0); // Calculate the current distance based on the elapsed time + alongPath(start, end, location -> { + double distanceFromStart = start.distance(location); + if (distanceFromStart <= currentDistance) { + // Spawn particles for visual effects + location.getWorld().spawnParticle(Particle.END_ROD, location, 1, 0.5, 0.5, 0.5, 0); // Increase the count and speed for a bigger beam + location.getWorld().spawnParticle(Particle.REDSTONE, location, 1, 0.5, 0.5, 0.5, 0, + new Particle.DustOptions(Color.fromRGB(144, 0, 255), 1)); + if (ticks % 8 == 0) location.getWorld().spawnParticle(Particle.SONIC_BOOM, location, 1); + + // Deal damage to nearby entities + player.getWorld().getNearbyEntities(location, 1, 1, 1).forEach(entity -> { + if (entity instanceof Damageable dEntity && !entity.equals(player)) { + dEntity.damage(ability.getStrength() * 10); // Assuming the main beam deals 10 times the ability's strength as damage + // knock the entity back and play a sound + entity.setVelocity(entity.getLocation().toVector().subtract(location.toVector()).normalize().multiply(0.5)); + entity.getWorld().playSound(entity.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1, 0); + // particle impact + entity.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, entity.getLocation(), 1, 0.5, 0.5, 0.5, 0); + } + }); + } + }); + ticks += 4; + } else { + // Stop the task after 1 second + this.cancel(); + } + } + }.runTaskTimer(EvoCraft.getPlugin(), 0L, 4L); // Run every tick (1/20th of a second) + } + + public static class ShieldListener implements Listener { + private static final Map shields = new HashMap<>(); + + @EventHandler + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.getEntity() instanceof Player) { + Player player = (Player) event.getEntity(); + ArmorStand shield = shields.get(player); + if (shield != null && isInFront(player, event.getDamager())) { + event.setCancelled(true); + // Decrease shield health + shield.setHealth(shield.getHealth() - event.getFinalDamage()); + + player.playSound(player.getLocation(), Sound.BLOCK_GLASS_BREAK, 1.0f, 0f); + + // Play sound effect with pitch relative to shield's health + float pitch = (float) shield.getHealth() / 20f; // Assuming max health is 20 + + if (shield.getHealth() <= 0) { + shields.remove(player); + shield.remove(); + + // Play breaking sound effect + + player.playSound(player.getLocation(), Sound.BLOCK_BEACON_DEACTIVATE, 1, pitch); + + // Play break animation + ActiveModel model = ModelEngineAPI.createActiveModel("mana_rune"); + ModeledEntity entity = ModelEngineAPI.createModeledEntity(shield); + entity.addModel(model, true); + model.getAnimationHandler().playAnimation("death", 1, 1, 1, false); + } + } + } + } + + public static void addShield(Player player, ArmorStand shield) { + shields.put(player, shield); + } + + public static void removeShield(Player player) { + shields.remove(player); + } + } + + + public static void runeShieldAbility(PlayerInteractEvent event, Player player, ClassAbility ability) { + // Spawn the rune shield model in front of the player + Location shieldLocation = player.getLocation().add(player.getLocation().getDirection().multiply(1)); + ActiveModel model = ModelEngineAPI.createActiveModel("mana_rune"); + + ArmorStand stand = player.getWorld().spawn(shieldLocation, ArmorStand.class); + stand.setGravity(false); + stand.setVisible(false); + stand.setCollidable(true); // Prevent entities from passing through + stand.setHealth(20); // Set shield health (10 seconds * 20 health per second) + ModeledEntity entity = ModelEngineAPI.createModeledEntity(stand); + entity.addModel(model, true); + model.getAnimationHandler().playAnimation("idle", 1, 1, 1, true); + + // Add the shield to the listener + ShieldListener.addShield(player, stand); + + new BukkitRunnable() { + @Override + public void run() { + if (stand.isValid()) { + double newHealth = stand.getHealth() - 1; // Decrease health by 1 each second + if (newHealth <= 0) { + // If health is 0 or less, remove the shield + ShieldListener.removeShield(player); + stand.remove(); + } else { + // Otherwise, update the shield's health + stand.setHealth(newHealth); + } + } else { + this.cancel(); + } + } + }.runTaskTimer(EvoCraft.getPlugin(), 0L, 20L); + + // Task to make the shield follow the player + new BukkitRunnable() { + @Override + public void run() { + if (stand.isValid()) { + stand.teleport(player.getLocation().add(player.getLocation().getDirection().multiply(1))); + } else { + this.cancel(); + } + } + }.runTaskTimer(EvoCraft.getPlugin(), 0L, 1L); // Update every tick + + // Remove the shield after a certain duration + new BukkitRunnable() { + @Override + public void run() { + if (stand.isValid()) { + ShieldListener.removeShield(player); + stand.remove(); + } + } + }.runTaskLater(EvoCraft.getPlugin(), 20 * 10); // Remove the shield after 10 seconds + } + + private static boolean isInFront(Player player, Entity entity) { + Vector toEntity = entity.getLocation().toVector().subtract(player.getLocation().toVector()).normalize(); + Vector direction = player.getLocation().getDirection(); + return direction.dot(toEntity) >= 0; // This checks if the entity is in front of the player + } + + public static void runeIlluminatingAura(PlayerInteractEvent event, Player player, ClassAbility ability) { + runeShieldAbility(event, player, ability); + // Create a light source at the player's location + + } + + public static void arcaneResonance(PlayerInteractEvent event, Player player, ClassAbility ability) { + + } + + public static void bloodlustAbility(PlayerInteractEvent event, Player player, ClassAbility ability){ + player.addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 1200, 1) ); + } + + public static void tripleSlashAbility(PlayerInteractEvent event, Player player, ClassAbility ability) { + + } + + public static void bullRushAbility(PlayerInteractEvent event, Player player, ClassAbility ability) { + + } + public static ArrayList counterStrikeActive = new ArrayList<>(); + public static void counterstrikeAbility(PlayerInteractEvent event, Player player, ClassAbility ability) { + counterStrikeActive.add(player); + player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 50, 200)); + player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW_FALLING, 50, 200)); + player.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 50, 200)); + new BukkitRunnable(){ + @Override + public void run() { + counterStrikeActive.remove(player); + } + }.runTaskLater(EvoCraft.getPlugin(), 50); + } + + public static void agilityBloodlust(PlayerInteractEvent event, Player player, ClassAbility ability) { + + } + + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface SaveState { + } +} \ No newline at end of file diff --git a/src/main/java/me/zenox/evocraft/abilities/CooldownManager.java b/src/main/java/me/zenox/evocraft/abilities/CooldownManager.java new file mode 100644 index 0000000..78d04be --- /dev/null +++ b/src/main/java/me/zenox/evocraft/abilities/CooldownManager.java @@ -0,0 +1,99 @@ +package me.zenox.evocraft.abilities; + +import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.util.Util; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * Manages the cooldowns and charges for abilities + */ +public class CooldownManager implements Listener { + private final Map> chargeMap = new HashMap<>(); + private final Map> rechargeTasks = new HashMap<>(); + + public CooldownManager() { + Bukkit.getPluginManager().registerEvents(this, EvoCraft.getPlugin()); + } + + public boolean isOnCooldown(Player player, ClassAbility ability) { + return getCharges(player, ability) == 0; + } + + public int getCharges(@NotNull Player player, ClassAbility ability) { + chargeMap.putIfAbsent(player.getUniqueId(), new HashMap<>()); + return chargeMap.get(player.getUniqueId()).getOrDefault(ability, ability.getCharges()); + } + + /** + * Consumes a charge of the ability and returns the amount of charges left + * @param player + * @param ability + * @return the amount of charges left + */ + public int consumeCharge(@NotNull Player player, ClassAbility ability) { + if (isOnCooldown(player, ability)) + throw new IllegalStateException("You cannot use an ability when you have zero charges left."); + Map playerCharges = chargeMap.get(player.getUniqueId()); + playerCharges.put(ability, getCharges(player, ability) - 1); + rechargeAbility(player, ability); + return getCharges(player, ability); + } + + public void rechargeAbility(Player player, @NotNull ClassAbility ability) { + UUID playerId = player.getUniqueId(); + chargeMap.putIfAbsent(playerId, new HashMap<>()); + rechargeTasks.putIfAbsent(playerId, new HashMap<>()); + + if (rechargeTasks.get(playerId).containsKey(ability)) { + // A recharge task is already running for this ability + return; + } + + int chargeTime = ability.getChargeTime() * 20; + BukkitRunnable task = new BukkitRunnable() { + @Override + public void run() { + ability.executeAsPlayer(player, (ability) -> { + if (getCharges(player, ability) < ability.getCharges()) { + chargeMap.get(playerId).put(ability, getCharges(player, ability) + 1); + Util.sendActionBar(player, " &6(+1 %s charge) (%d/%d)".formatted(ability.getDisplayName(), getCharges(player, ability), ability.getCharges())); + } else { + cancel(); + rechargeTasks.get(playerId).remove(ability); + } + + if (ability.getChargeTime() * 20 != chargeTime) { + cancel(); + rechargeTasks.get(playerId).remove(ability); + this.runTaskTimer(EvoCraft.getPlugin(), ability.getChargeTime(), ability.getChargeTime()); + } + }); + } + }; + + rechargeTasks.get(playerId).put(ability, task); + task.runTaskTimer(EvoCraft.getPlugin(), chargeTime, chargeTime); + } + + @EventHandler + public void onPlayerLeave(PlayerQuitEvent e) { + UUID playerId = e.getPlayer().getUniqueId(); + chargeMap.remove(playerId); + if (rechargeTasks.containsKey(playerId)) { + for (BukkitRunnable task : rechargeTasks.get(playerId).values()) { + task.cancel(); // Cancel any running tasks + } + rechargeTasks.remove(playerId); + } + } +} diff --git a/src/main/java/me/zenox/evocraft/abilities/ElementalFlux.java b/src/main/java/me/zenox/evocraft/abilities/ElementalFlux.java index d745a55..920e4c8 100644 --- a/src/main/java/me/zenox/evocraft/abilities/ElementalFlux.java +++ b/src/main/java/me/zenox/evocraft/abilities/ElementalFlux.java @@ -1,5 +1,6 @@ package me.zenox.evocraft.abilities; +import me.zenox.evocraft.abilities.itemabilities.ItemAbility; import me.zenox.evocraft.item.ComplexItemMeta; import me.zenox.evocraft.item.ComplexItemStack; import me.zenox.evocraft.item.LoreEntry; diff --git a/src/main/java/me/zenox/evocraft/abilities/EventAbility.java b/src/main/java/me/zenox/evocraft/abilities/EventAbility.java new file mode 100644 index 0000000..65891c4 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/abilities/EventAbility.java @@ -0,0 +1,130 @@ +package me.zenox.evocraft.abilities; + +import me.zenox.evocraft.Slot; +import me.zenox.evocraft.item.ComplexItem; +import me.zenox.evocraft.util.TriConsumer; +import me.zenox.evocraft.util.Util; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + + +public abstract class EventAbility extends Ability { + + private final Class eventType; + private final Slot slot; + @ClassAbility.SaveState + protected TriConsumer executable; + + protected EventAbility(String id, int manaCost, double cooldown, Slot slot) { + this(id, manaCost, cooldown, slot, false); + this.executable = this::runExecutable; + } + + protected EventAbility(String id, int manaCost, double cooldown, Slot slot, TriConsumer executable) { + this(id, manaCost, cooldown, slot, false); + this.executable = executable; + } + + protected EventAbility(@NotNull AbilitySettings settings){ + this(settings.getId(), settings.getManaCost(), settings.getCooldown(), settings.getSlot(), settings.isPassive()); + } + + protected EventAbility(@NotNull AbilitySettings settings, TriConsumer executable){ + this(settings.getId(), settings.getManaCost(), settings.getCooldown(), settings.getSlot(), settings.isPassive()); + this.executable = executable; + } + + /** + * Internal constructor because exectuable go brr + * + * @param id The unique identifier of the ability + * @param manaCost The mana cost-per usage of the ability + * @param cooldown The cooldown of the ability, how long before it can be used again + * @param slot The slot that the item that contains the ability has to be in, i.e. main hand, head, etc + * @param isPassive Whether the ability is passive + */ + private EventAbility(String id, int manaCost, double cooldown, Slot slot, boolean isPassive) { + super(id, manaCost, cooldown, isPassive); + this.slot = slot; + + this.eventType = (Class) getType(); + if(this.eventType == null) throw new NullPointerException("Event type is null"); + + for (Ability ability : + registeredAbilities) { + if (ability.getId().equalsIgnoreCase(id)) { + Util.logToConsole("Duplicate Ability ID: " + id + " | Exact Match: " + ability.equals(this)); + throw new IllegalArgumentException("Ability ID cannot be duplicate"); + } + } + + Ability.registeredAbilities.add(this); + } + + @Override + public void useAbility(Event event) { + if (!isValidEvent(event)) return; + T e = (T) event; + Player p = getPlayerOfEvent(e); + ItemStack item = getValidItem(p, e); + + if (item == null) return; + + if (isAbilityOnCooldown(p)) { + sendCooldownMessage(p); + return; + } + + if (notEnoughMana(p, this.getManaCost())) { + sendManaInsufficientMessage(p); + return; + } + + deductMana(p, this.getManaCost()); + this.executable.accept(e, p, item); + setAbilityCooldown(p); + } + + protected boolean isValidEvent(Event event) { + if (!this.eventType.isInstance(event)) return false; + T e = (T) event; + return checkEvent(e); + } + + protected ItemStack getValidItem(Player p, T e) { + List items = getItem(p, e); + for (ItemStack i : items) { + if (i == null || i.getType() == Material.AIR || i.getItemMeta() == null) continue; + if (!ComplexItem.of(i).getAbilities().contains(this)) continue; + return i; + } + return null; + } + + protected abstract boolean checkEvent(T e); + + protected abstract Player getPlayerOfEvent(T e); + + protected abstract List getItem(Player p, T e); + + public Slot getSlot() { + return this.slot; + } + + public Class getEventType() { + return eventType; + } + + public TriConsumer getExecutable() { + return this.executable; + } + + public void setExecutable(TriConsumer executable) { + this.executable = executable; + } +} diff --git a/src/main/java/me/zenox/evocraft/abilities/Modifier.java b/src/main/java/me/zenox/evocraft/abilities/Modifier.java new file mode 100644 index 0000000..61bfa20 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/abilities/Modifier.java @@ -0,0 +1,140 @@ +package me.zenox.evocraft.abilities; + +import me.zenox.evocraft.data.TranslatableList; +import me.zenox.evocraft.data.TranslatableText; +import me.zenox.evocraft.util.TriConsumer; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerInteractEvent; + +public abstract class Modifier { + + private final String id; + private final TranslatableText name; + private final TranslatableList lore; + + public enum Type { + MANA_COST { + @Override + Modifier create(String id, double value) { + return new Modifier(id) { + @Override + void modify(ClassAbility ability) { + ability.setManaCost(ability.getManaCost() + (int) value); + } + }; + } + }, + COOLDOWN { + @Override + Modifier create(String id, double value) { + return new Modifier(id) { + @Override + void modify(ClassAbility ability) { + ability.setCooldown(ability.getCooldown() + value); + } + }; + } + }, + EXECUTABLE { + @Override + Modifier create(String id, TriConsumer executable) { + return new Modifier(id) { + @Override + void modify(ClassAbility ability) { + ability.setExecutable(executable); + } + }; + } + }, + RANGE { + @Override + Modifier create(String id, double value) { + return new Modifier(id) { + @Override + void modify(ClassAbility ability) { + ability.setRange(ability.getRange() + (int) value); + } + }; + } + }, + CHARGE { + @Override + Modifier create(String id, double value) { + return new Modifier(id) { + @Override + void modify(ClassAbility ability) { + ability.setCharges(ability.getCharges() + (int) value); + } + }; + } + }, + STRENGTH { + @Override + Modifier create(String id, double value) { + return new Modifier(id) { + @Override + void modify(ClassAbility ability) { + ability.setStrength(ability.getStrength() + (int) value); + } + }; + } + }, + MULTI { + @Override + Modifier create(String id, Modifier ... modifiers) { + return new Modifier(id) { + @Override + void modify(ClassAbility ability) { + for (Modifier modifier : modifiers) { + modifier.modify(ability); + } + } + }; + } + }; + + Modifier create(String id, double value) { + throw new UnsupportedOperationException("This operation is not supported for type: " + this); + } + + Modifier create(String id, TriConsumer executable) { + throw new UnsupportedOperationException("This operation is not supported for type: " + this); + } + + Modifier create(String id, Modifier ... modifiers) { + throw new UnsupportedOperationException("This operation is not supported for type: " + this); + } + } + + private Modifier(String id) { + this.id = id; + this.name = new TranslatableText(TranslatableText.Type.MODIFIER_NAME + "-" + id); + this.lore = new TranslatableList(TranslatableText.Type.MODIFIER_LORE + "-" + id); + } + + public static Modifier of(Type type, String id, double value) { + return type.create(id, value); + } + + public static Modifier of(Type type, String id, TriConsumer executable) { + return type.create(id, executable); + } + + public static Modifier of(Type type, String id, Modifier ... modifiers) { + return type.create(id, modifiers); + } + + abstract void modify(ClassAbility ability); + + public String id() { + return id; + } + + public TranslatableText name() { + return name; + } + + public TranslatableList lore() { + return lore; + } +} diff --git a/src/main/java/me/zenox/evocraft/abilities/MoveAbility.java b/src/main/java/me/zenox/evocraft/abilities/MoveAbility.java deleted file mode 100644 index a0eb7c2..0000000 --- a/src/main/java/me/zenox/evocraft/abilities/MoveAbility.java +++ /dev/null @@ -1,71 +0,0 @@ -package me.zenox.evocraft.abilities; - -import me.zenox.evocraft.Slot; -import me.zenox.evocraft.EvoCraft; -import me.zenox.evocraft.util.TriConsumer; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Particle; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.List; -import java.util.Random; - -public class MoveAbility extends Ability { - - public MoveAbility(AbilitySettings settings) { - super(settings); - } - - public MoveAbility(AbilitySettings settings, TriConsumer executable) { - super(settings, executable); - } - - public MoveAbility(String id, int manaCost, double cooldown, TriConsumer executable) { - super(id, manaCost, cooldown, Slot.ARMOR, executable); - } - - @Override - protected boolean checkEvent(PlayerMoveEvent e) { - return e instanceof PlayerMoveEvent; - } - - @Override - Player getPlayerOfEvent(PlayerMoveEvent e) { - return ((PlayerMoveEvent) e).getPlayer(); - } - - @Override - List getItem(Player p, PlayerMoveEvent e) { - return this.getSlot().item(p); - } - - // Static ability executables - public static void lavaGliderAbility(PlayerMoveEvent e, Player p, ItemStack item) { - // If the player is in lava - if (p.getWorld().getBlockAt(p.getLocation()).getType().equals(Material.LAVA) - || p.getWorld().getBlockAt(p.getLocation().subtract(0, 1, 0)).getType().equals(Material.LAVA)){ - p.setWalkSpeed(0.5f); - - Random r = new Random(); - for (int i = 0; i < 2; i++) { - // Spawn a LAVA particle that is randomized but near player's location - Location loc = p.getLocation(); - loc.add(r.nextDouble() - 0.5d, r.nextDouble() - 0.5d, r.nextDouble() - 0.5d); - p.getWorld().spawnParticle(Particle.LAVA, loc, 1); - } - new BukkitRunnable() { - @Override - public void run() { - p.setWalkSpeed(0.2f); - } - }.runTaskLater(EvoCraft.getPlugin(), 1); - } - else p.setWalkSpeed(0.2f); - - } - -} diff --git a/src/main/java/me/zenox/evocraft/abilities/AttackAbility.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/AttackAbility.java similarity index 90% rename from src/main/java/me/zenox/evocraft/abilities/AttackAbility.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/AttackAbility.java index 932fefe..8429dde 100644 --- a/src/main/java/me/zenox/evocraft/abilities/AttackAbility.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/AttackAbility.java @@ -1,8 +1,10 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities; import me.zenox.evocraft.Slot; import me.zenox.evocraft.EvoCraft; -import me.zenox.evocraft.util.Geo; +import me.zenox.evocraft.abilities.AbilitySettings; +import me.zenox.evocraft.abilities.EventAbility; +import me.zenox.evocraft.util.GeometryUtils; import me.zenox.evocraft.util.TriConsumer; import me.zenox.evocraft.util.Util; import org.bukkit.*; @@ -20,7 +22,7 @@ import java.util.List; import java.util.Random; -public class AttackAbility extends Ability { +public class AttackAbility extends EventAbility { public AttackAbility(AbilitySettings settings) { @@ -41,12 +43,12 @@ protected boolean checkEvent(EntityDamageByEntityEvent event) { } @Override - Player getPlayerOfEvent(EntityDamageByEntityEvent e) { + protected Player getPlayerOfEvent(EntityDamageByEntityEvent e) { return ((Player) e.getDamager()); } @Override - List getItem(Player p, EntityDamageByEntityEvent e) { + protected List getItem(Player p, EntityDamageByEntityEvent e) { return this.getSlot().item(p); } @@ -122,7 +124,7 @@ public void run() { if (stacks >= 3) { // Create Dodecahedron - List edgedDodecahedron = Geo.lerpEdges(Geo.makeDodecahedron(p.getLocation().toVector(), 2), 7); + List edgedDodecahedron = GeometryUtils.lerpEdges(GeometryUtils.makeDodecahedron(p.getLocation().toVector(), 2), 7); for (Vector v : edgedDodecahedron) { Particle.DustOptions dustOptions = new Particle.DustOptions(Color.fromRGB(5, 165, 255), 0.6F); diff --git a/src/main/java/me/zenox/evocraft/abilities/FullSetArmorAbility.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetArmorAbility.java similarity index 81% rename from src/main/java/me/zenox/evocraft/abilities/FullSetArmorAbility.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetArmorAbility.java index 0653050..d8aa863 100644 --- a/src/main/java/me/zenox/evocraft/abilities/FullSetArmorAbility.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetArmorAbility.java @@ -1,7 +1,9 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities; import me.zenox.evocraft.Slot; -import me.zenox.evocraft.item.ComplexItemStack; +import me.zenox.evocraft.abilities.AbilitySettings; +import me.zenox.evocraft.abilities.EventAbility; +import me.zenox.evocraft.item.ComplexItem; import me.zenox.evocraft.util.TriConsumer; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -10,7 +12,7 @@ /** * General Armor Ability with no class */ -public abstract class FullSetArmorAbility extends Ability { +public abstract class FullSetArmorAbility extends EventAbility { public FullSetArmorAbility(AbilitySettings settings) { super(settings); } @@ -27,7 +29,7 @@ public FullSetArmorAbility(String id, int manaCost, double cooldown, TriConsumer protected boolean checkEvent(T e) { return checkEventExec(e) && Slot.ARMOR.item(getPlayerOfEvent(e)).stream().allMatch(itemStack -> { try { - return ComplexItemStack.of(itemStack).getAbilities().contains(this); + return ComplexItem.of(itemStack).getAbilities().contains(this); } catch (NullPointerException exception){ return false; } diff --git a/src/main/java/me/zenox/evocraft/abilities/FullSetAttackAbility.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetAttackAbility.java similarity index 86% rename from src/main/java/me/zenox/evocraft/abilities/FullSetAttackAbility.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetAttackAbility.java index 7eee2f2..bce86fc 100644 --- a/src/main/java/me/zenox/evocraft/abilities/FullSetAttackAbility.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetAttackAbility.java @@ -1,5 +1,6 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities; +import me.zenox.evocraft.abilities.AbilitySettings; import me.zenox.evocraft.util.TriConsumer; import me.zenox.evocraft.util.Util; import org.bukkit.entity.Player; @@ -29,12 +30,12 @@ protected boolean checkEventExec(EntityDamageByEntityEvent e) { } @Override - Player getPlayerOfEvent(EntityDamageByEntityEvent e) { + protected Player getPlayerOfEvent(EntityDamageByEntityEvent e) { return ((Player) e.getDamager()); } @Override - List getItem(Player p, EntityDamageByEntityEvent e) { + protected List getItem(Player p, EntityDamageByEntityEvent e) { return this.getSlot().item(p); } diff --git a/src/main/java/me/zenox/evocraft/abilities/FullSetDamagedAbility.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetDamagedAbility.java similarity index 88% rename from src/main/java/me/zenox/evocraft/abilities/FullSetDamagedAbility.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetDamagedAbility.java index d2dbdcc..46d3ec9 100644 --- a/src/main/java/me/zenox/evocraft/abilities/FullSetDamagedAbility.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetDamagedAbility.java @@ -1,5 +1,6 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities; +import me.zenox.evocraft.abilities.AbilitySettings; import me.zenox.evocraft.util.TriConsumer; import me.zenox.evocraft.util.Util; import org.bukkit.entity.Player; @@ -36,12 +37,12 @@ protected boolean checkEventExec(EntityDamageEvent e) { } @Override - Player getPlayerOfEvent(EntityDamageEvent e) { + protected Player getPlayerOfEvent(EntityDamageEvent e) { return ((Player) e.getEntity()); } @Override - List getItem(Player p, EntityDamageEvent e) { + protected List getItem(Player p, EntityDamageEvent e) { return this.getSlot().item(p); } diff --git a/src/main/java/me/zenox/evocraft/abilities/FullSetEntityDamagedAbility.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetEntityDamagedAbility.java similarity index 89% rename from src/main/java/me/zenox/evocraft/abilities/FullSetEntityDamagedAbility.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetEntityDamagedAbility.java index fed346a..95c9fd1 100644 --- a/src/main/java/me/zenox/evocraft/abilities/FullSetEntityDamagedAbility.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/FullSetEntityDamagedAbility.java @@ -1,5 +1,6 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities; +import me.zenox.evocraft.abilities.AbilitySettings; import me.zenox.evocraft.util.TriConsumer; import me.zenox.evocraft.util.Util; import org.bukkit.Color; @@ -30,12 +31,12 @@ protected boolean checkEventExec(EntityDamageByEntityEvent e) { } @Override - Player getPlayerOfEvent(EntityDamageByEntityEvent e) { + protected Player getPlayerOfEvent(EntityDamageByEntityEvent e) { return ((Player) e.getEntity()); } @Override - List getItem(Player p, EntityDamageByEntityEvent e) { + protected List getItem(Player p, EntityDamageByEntityEvent e) { return this.getSlot().item(p); } diff --git a/src/main/java/me/zenox/evocraft/abilities/ItemAbility.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/ItemAbility.java similarity index 89% rename from src/main/java/me/zenox/evocraft/abilities/ItemAbility.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/ItemAbility.java index c0cb386..0058946 100644 --- a/src/main/java/me/zenox/evocraft/abilities/ItemAbility.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/ItemAbility.java @@ -1,6 +1,5 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities; -import com.archyx.aureliumskills.api.AureliumAPI; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketContainer; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -12,14 +11,20 @@ import com.sk89q.worldguard.protection.regions.RegionQuery; import com.ticxo.modelengine.api.ModelEngineAPI; import com.ticxo.modelengine.api.model.ModeledEntity; +import dev.aurelium.auraskills.api.trait.Traits; +import dev.aurelium.auraskills.api.user.SkillsUser; import it.unimi.dsi.fastutil.ints.IntArrayList; -import me.zenox.evocraft.Slot; import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.Slot; +import me.zenox.evocraft.abilities.AbilitySettings; +import me.zenox.evocraft.abilities.ElementalFlux; +import me.zenox.evocraft.abilities.EventAbility; +import me.zenox.evocraft.abilities.itemabilities.specific.EmberAttune; import me.zenox.evocraft.item.ComplexItemMeta; import me.zenox.evocraft.item.ComplexItemStack; import me.zenox.evocraft.item.ItemRegistry; import me.zenox.evocraft.persistence.NBTEditor; -import me.zenox.evocraft.util.Geo; +import me.zenox.evocraft.util.GeometryUtils; import me.zenox.evocraft.util.TriConsumer; import me.zenox.evocraft.util.Util; import org.bukkit.*; @@ -44,7 +49,7 @@ import static me.zenox.evocraft.item.ItemRegistry.TOTEM_POLE; import static me.zenox.evocraft.util.Util.getNearbyBlocks; -public class ItemAbility extends Ability { +public class ItemAbility extends EventAbility { private static final int SHARD_SPEED = 3; private static final int SHARD_RADIUS = 3; private final AbilityAction action; @@ -81,12 +86,12 @@ public ItemAbility(String id, AbilityAction action, int manaCost, double cooldow } @Override - Player getPlayerOfEvent(PlayerInteractEvent e) { + protected Player getPlayerOfEvent(PlayerInteractEvent e) { return e.getPlayer(); } @Override - List getItem(Player p, PlayerInteractEvent e) { + protected List getItem(Player p, PlayerInteractEvent e) { return Arrays.stream(new ItemStack[]{e.getItem()}).filter(Objects::nonNull).toList(); } @@ -96,7 +101,7 @@ public AbilityAction getAction() { @Override public boolean checkEvent(PlayerInteractEvent event) { - return action.isAction(event.getAction(), event.getPlayer().isSneaking()); + return action.isAction(event.getAction()) && !event.getPlayer().isSneaking(); } /** @@ -138,7 +143,7 @@ public static void soulRiftAbility(PlayerInteractEvent event, Player p, ItemStac @Override public void run() { // Particle Magic - List dodecahedron = Geo.makeDodecahedron(loc.toVector(), 2); + List dodecahedron = GeometryUtils.makeDodecahedron(loc.toVector(), 2); for (Vector v : dodecahedron) { Particle.DustOptions dustOptions = new Particle.DustOptions(Color.fromRGB(0, 187, 215), 0.5F); w.spawnParticle(Particle.REDSTONE, v.toLocation(w).add(0, 0.5 + Math.sin(count) / 4, 0), 1, dustOptions); @@ -809,6 +814,9 @@ public void run() { } public static void emberShootAbility(PlayerInteractEvent event, Player p, ItemStack item) { + + SkillsUser user = Util.getSkillsUser(p); + ComplexItemMeta complexMeta = ComplexItemStack.of(item).getComplexMeta(); Location eyeLoc = p.getEyeLocation(); @@ -817,11 +825,11 @@ public static void emberShootAbility(PlayerInteractEvent event, Player p, ItemSt if (complexMeta.getVariable(EmberAttune.ATTUNEMENT_VARIABLE_TYPE).getValue().equals(EmberAttune.Attunement.BLAZEBORN)) { Fireball f = (Fireball) eyeLoc.getWorld().spawnEntity(eyeLoc.add(eyeLoc.getDirection()), EntityType.FIREBALL); - f.setVelocity(eyeLoc.getDirection().normalize().multiply(Math.min(5, AureliumAPI.getMaxMana(event.getPlayer()) / 75))); + f.setVelocity(eyeLoc.getDirection().normalize().multiply(Math.min(5, user.getMaxMana() / 75))); f.setMetadata("dmgEnv", new FixedMetadataValue(EvoCraft.getPlugin(), false)); f.setMetadata("knockback", new FixedMetadataValue(EvoCraft.getPlugin(), 2)); f.setShooter(p); - f.setYield(((float) Math.sqrt(AureliumAPI.getMaxMana(p))) / 10f); + f.setYield(((float) Math.sqrt(user.getMaxMana())) / 10f); // get rid of the fireball after 10 seconds new BukkitRunnable() { @@ -833,10 +841,10 @@ public void run() { } else if (complexMeta.getVariable(EmberAttune.ATTUNEMENT_VARIABLE_TYPE).getValue().equals(EmberAttune.Attunement.DARKSOUL)) { WitherSkull f = (WitherSkull) eyeLoc.getWorld().spawnEntity(eyeLoc.add(eyeLoc.getDirection()), EntityType.WITHER_SKULL); - f.setVelocity(eyeLoc.getDirection().normalize().multiply(Math.min(5, AureliumAPI.getMaxMana(event.getPlayer()) / 50))); + f.setVelocity(eyeLoc.getDirection().normalize().multiply(Math.min(5, user.getMaxMana() / 50))); f.setMetadata("dmgEnv", new FixedMetadataValue(EvoCraft.getPlugin(), false)); f.setShooter(p); - f.setYield((float) Math.sqrt(AureliumAPI.getMaxMana(p)) / 6f); + f.setYield((float) Math.sqrt(user.getMaxMana()) / 6f); // get rid of the fireball after 10 seconds new BukkitRunnable() { @@ -859,82 +867,6 @@ public static void smallEmberShootAbility(PlayerInteractEvent event, Player p, I f.setShooter(p); } - public static void startButtonAbility(PlayerInteractEvent playerInteractEvent, Player player, ItemStack itemStack) { - // Check if the player has started using the "hasStarted" metadata value - try { - if (player.getMetadata("hasStarted").size() > 0 || player.getMetadata("hasStarted").get(0).asBoolean()) - return; - } catch (IndexOutOfBoundsException ignored){ - - } - - player.setMetadata("hasStarted", new FixedMetadataValue(EvoCraft.getPlugin(), true)); - - BukkitRunnable startup = new BukkitRunnable(){ - @Override - public void run() { - Util.sendMessage(player, "&aStarting Windows XP... &a&l(" + 100 + ")%", false); - EvoCraft.getChapterManager().getChapter(player).progress(player, playerInteractEvent); - } - }; - - new BukkitRunnable(){ - int a = 0; - @Override - public void run() { - if(a == 0) Util.sendMessage(player, "&aStarting Windows XP...", false); - else Util.sendMessage(player, "&aStarting Windows XP... &7(" + Math.min(100, a) + ")%", false); - a += Util.round(new Random().nextDouble()*10, 1); - if(a >= 100) { - cancel(); - player.playSound(player.getLocation(), "story.0.startup", 1, 1); - startup.runTaskLater(EvoCraft.getPlugin(), 120); - } - } - }.runTaskTimer(EvoCraft.getPlugin(), 5, 4); - } - - public static void portalizerAbility(PlayerInteractEvent playerInteractEvent, Player player, ItemStack itemStack) { - if(playerInteractEvent.getAction() == Action.RIGHT_CLICK_BLOCK) { - Block block = playerInteractEvent.getClickedBlock(); - if(block != null) { - if(block.getType() == Material.WHITE_STAINED_GLASS) { - itemStack.setAmount(0); - player.playSound(player.getLocation(), Sound.BLOCK_BEACON_ACTIVATE, 1, 1); - player.playSound(player.getLocation(), Sound.BLOCK_BEACON_POWER_SELECT, 1, 1f); - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "mm m spawn -s LightCrystalCharger 1 " + player.getWorld() + "," + -347 + "," + -61 + "," + -511); - new BukkitRunnable(){ - @Override - public void run() { - player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 0.5f, 0.8f); - player.teleport(new Location(player.getServer().getWorld("flat"), -369, -53, -594)); - player.setBedSpawnLocation(new Location(player.getServer().getWorld("flat"), -369, -53, -594), true); - Util.sendMessage(player, "&b100BCE | &8The Desolated Temple", false); - // Play second voiceover sounds - player.playSound(player.getLocation(), "story.chapter.1.backstory_2", 20f, 1f); - } - }.runTaskLater(EvoCraft.getPlugin(), 80); - - } else if (block.getType() == Material.TINTED_GLASS) { - itemStack.setAmount(0); - player.playSound(player.getLocation(), Sound.BLOCK_BEACON_ACTIVATE, 1, 0.5f); - player.playSound(player.getLocation(), Sound.BLOCK_BEACON_POWER_SELECT, 1, 0.5f); - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "mm m spawn -s DarkCrystalCharger 1 " + player.getWorld() + "," + -369 + "," + -61 + "," + -594); - new BukkitRunnable(){ - @Override - public void run() { - player.playSound(player.getLocation(), Sound.BLOCK_PORTAL_TRAVEL, 1, 1); - player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, 0.8f); - - Util.sendMessage(player, "&bPresent Day | &aEnsildia", false); - EvoCraft.getChapterManager().getChapter(player).progress(player, playerInteractEvent); - } - }.runTaskLater(EvoCraft.getPlugin(), 80); - } - } - } - } - public static void snowShotAbility(PlayerInteractEvent playerInteractEvent, @NotNull Player player, ItemStack itemStack) { // Summon a snowball and shoot it, then apply a metadata tag that will be used to check if the snowball is a snowball shot by the player Snowball snowball = player.launchProjectile(Snowball.class, player.getLocation().getDirection().multiply(3)); @@ -976,8 +908,10 @@ public void run() { } public static void manaBoostAbility(PlayerInteractEvent event, Player player, ItemStack itemStack) { + SkillsUser user = Util.getSkillsUser(player); + // An ability that refuels the player to full mana instantaneously, and grants them 2x mana regeneration for the next 10 seconds - AureliumAPI.setMana(player, AureliumAPI.getMaxMana(player)); + user.setMana(user.getMaxMana()); // Send and action bar Util.sendActionBar(player, "&b&lMana Refueled!"); // Play a sound @@ -1002,9 +936,9 @@ public void run() { cancel(); } // Get the players current mana regeneration - double manaRegen = AureliumAPI.getManaRegen(player); + double manaRegen = user.getEffectiveTraitLevel(Traits.MANA_REGEN); // Add that amount to the player's mana - AureliumAPI.setMana(player, Math.min(AureliumAPI.getMaxMana(player), AureliumAPI.getMana(player) + manaRegen)); + user.setMana(Math.min(user.getMaxMana(), user.getMana() + manaRegen)); } }.runTaskTimer(EvoCraft.getPlugin(), 0, 20); @@ -1099,32 +1033,28 @@ public void run() { } public enum AbilityAction { - LEFT_CLICK_BLOCK("LEFT CLICK", new Action[]{Action.LEFT_CLICK_BLOCK}, false), - LEFT_CLICK_AIR("LEFT CLICK", new Action[]{Action.LEFT_CLICK_AIR}, false), - LEFT_CLICK_ALL("LEFT CLICK", new Action[]{Action.LEFT_CLICK_AIR, Action.LEFT_CLICK_BLOCK}, false), - SHIFT_LEFT_CLICK("SHIFT LEFT CLICK", new Action[]{Action.LEFT_CLICK_AIR, Action.LEFT_CLICK_BLOCK}, true), - RIGHT_CLICK_BLOCK("RIGHT CLICK", new Action[]{Action.RIGHT_CLICK_AIR}, false), - RIGHT_CLICK_AIR("RIGHT CLICK", new Action[]{Action.RIGHT_CLICK_BLOCK}, false), - RIGHT_CLICK_ALL("RIGHT CLICK", new Action[]{Action.RIGHT_CLICK_BLOCK, Action.RIGHT_CLICK_AIR}, false), - SHIFT_RIGHT_CLICK("SHIFT RIGHT CLICK", new Action[]{Action.RIGHT_CLICK_AIR, Action.RIGHT_CLICK_BLOCK}, true), - NONE("", new Action[]{}, false); + LEFT_CLICK_BLOCK("LEFT CLICK", new Action[]{Action.LEFT_CLICK_BLOCK}), + LEFT_CLICK_AIR("LEFT CLICK", new Action[]{Action.LEFT_CLICK_AIR}), + LEFT_CLICK_ALL("LEFT CLICK", new Action[]{Action.LEFT_CLICK_AIR, Action.LEFT_CLICK_BLOCK}), + RIGHT_CLICK_BLOCK("RIGHT CLICK", new Action[]{Action.RIGHT_CLICK_AIR}), + RIGHT_CLICK_AIR("RIGHT CLICK", new Action[]{Action.RIGHT_CLICK_BLOCK}), + RIGHT_CLICK_ALL("RIGHT CLICK", new Action[]{Action.RIGHT_CLICK_BLOCK, Action.RIGHT_CLICK_AIR}), + + NONE("", new Action[]{}); private final String name; private final Action[] actionList; - private final boolean requiresShift; - AbilityAction(String name, Action[] actionList, boolean requiresShift) { + AbilityAction(String name, Action[] actionList) { this.name = name; this.actionList = actionList; - this.requiresShift = requiresShift; } public String getName() { return this.name; } - public boolean isAction(Action action, boolean isCrouching) { - if (this.requiresShift && !isCrouching) return false; + public boolean isAction(Action action) { return Arrays.asList(actionList).contains(action); diff --git a/src/main/java/me/zenox/evocraft/abilities/Crucify.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Crucify.java similarity index 97% rename from src/main/java/me/zenox/evocraft/abilities/Crucify.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Crucify.java index c533688..7dc3beb 100644 --- a/src/main/java/me/zenox/evocraft/abilities/Crucify.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Crucify.java @@ -1,8 +1,8 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities.specific; import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.abilities.itemabilities.ItemAbility; import me.zenox.evocraft.item.ComplexItem; -import me.zenox.evocraft.item.ItemRegistry; import org.bukkit.*; import org.bukkit.entity.Damageable; import org.bukkit.entity.Entity; @@ -103,7 +103,7 @@ public void onPlayerDeath(PlayerDeathEvent e) { p.setMetadata("crucify_active", new FixedMetadataValue(EvoCraft.getPlugin(), false)); Inventory inv = p.getInventory(); for (ItemStack item : inv.getContents()) { - ComplexItem complexItemMaterial = ItemRegistry.byItem(item); + ComplexItem complexItemMaterial = ComplexItem.of(item); if (complexItemMaterial != null && complexItemMaterial.getId().equals(CRUCIFIED_AMULET.getId())) { item.setAmount(item.getAmount() - 1); diff --git a/src/main/java/me/zenox/evocraft/abilities/EmberAttune.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/EmberAttune.java similarity index 95% rename from src/main/java/me/zenox/evocraft/abilities/EmberAttune.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/EmberAttune.java index fabbcae..4394b74 100644 --- a/src/main/java/me/zenox/evocraft/abilities/EmberAttune.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/EmberAttune.java @@ -1,5 +1,6 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities.specific; +import me.zenox.evocraft.abilities.itemabilities.ItemAbility; import me.zenox.evocraft.item.ComplexItemMeta; import me.zenox.evocraft.item.ComplexItemStack; import me.zenox.evocraft.item.LoreEntry; diff --git a/src/main/java/me/zenox/evocraft/abilities/Psychic.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Psychic.java similarity index 90% rename from src/main/java/me/zenox/evocraft/abilities/Psychic.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Psychic.java index 708e0e7..7cab6c0 100644 --- a/src/main/java/me/zenox/evocraft/abilities/Psychic.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Psychic.java @@ -1,7 +1,5 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities.specific; -import com.archyx.aureliumskills.api.AureliumAPI; -import com.archyx.aureliumskills.stats.Stats; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.util.Location; import com.sk89q.worldguard.LocalPlayer; @@ -10,8 +8,13 @@ import com.sk89q.worldguard.protection.flags.Flags; import com.sk89q.worldguard.protection.regions.RegionContainer; import com.sk89q.worldguard.protection.regions.RegionQuery; -import me.zenox.evocraft.Slot; +import dev.aurelium.auraskills.api.AuraSkillsApi; +import dev.aurelium.auraskills.api.stat.StatModifier; +import dev.aurelium.auraskills.api.stat.Stats; +import dev.aurelium.auraskills.api.user.SkillsUser; import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.Slot; +import me.zenox.evocraft.abilities.itemabilities.ItemAbility; import me.zenox.evocraft.util.Util; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -35,6 +38,8 @@ public class Psychic extends ItemAbility implements Listener { + private static final AuraSkillsApi skillsApi = AuraSkillsApi.get(); + public Psychic() { super("psychic", AbilityAction.RIGHT_CLICK_ALL, 0, 0, Slot.MAIN_HAND); @@ -103,7 +108,7 @@ public void run() { dataContainer.set(key, PersistentDataType.INTEGER, count); p.playSound(p.getLocation(), Sound.ENTITY_ZOMBIE_VILLAGER_CONVERTED, 1, 1.2f); - AureliumAPI.addStatModifier(p, "evocraft:psychic_wisdom_buff_" + count, Stats.WISDOM, 50d); + skillsApi.getUser(p.getUniqueId()).addStatModifier(new StatModifier("evocraft:psychic_wisdom_buff_" + count, Stats.WISDOM , 50d)); } private void killPlayer(Player p, NamespacedKey key, PersistentDataContainer dataContainer) { @@ -111,6 +116,7 @@ private void killPlayer(Player p, NamespacedKey key, PersistentDataContainer dat p.setMetadata("evocraft:death_psychic", new FixedMetadataValue(EvoCraft.getPlugin(), true)); p.setHealth(0); p.damage(10, p); + SkillsUser user = skillsApi.getUser(p.getUniqueId()); new BukkitRunnable() { int count = 0; @@ -124,7 +130,7 @@ public void run() { } }.runTaskTimer(EvoCraft.getPlugin(), 0, 20); for (int i = 0; i < 20; i++) { - AureliumAPI.removeStatModifier(p, "evocraft:psychic_wisdom_buff_" + i); + user.removeStatModifier("evocraft:psychic_wisdom_buff_" + i); } } diff --git a/src/main/java/me/zenox/evocraft/abilities/Transcendence.java b/src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Transcendence.java similarity index 95% rename from src/main/java/me/zenox/evocraft/abilities/Transcendence.java rename to src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Transcendence.java index 0fdfb43..a9cbb6d 100644 --- a/src/main/java/me/zenox/evocraft/abilities/Transcendence.java +++ b/src/main/java/me/zenox/evocraft/abilities/itemabilities/specific/Transcendence.java @@ -1,5 +1,6 @@ -package me.zenox.evocraft.abilities; +package me.zenox.evocraft.abilities.itemabilities.specific; +import me.zenox.evocraft.abilities.itemabilities.ItemAbility; import me.zenox.evocraft.item.ComplexItemMeta; import me.zenox.evocraft.item.ComplexItemStack; import me.zenox.evocraft.item.LoreEntry; diff --git a/src/main/java/me/zenox/evocraft/attribute/Attribute.java b/src/main/java/me/zenox/evocraft/attribute/Attribute.java index 089f12a..9e5c12f 100644 --- a/src/main/java/me/zenox/evocraft/attribute/Attribute.java +++ b/src/main/java/me/zenox/evocraft/attribute/Attribute.java @@ -24,6 +24,7 @@ public abstract class Attribute implements Serializable { public Attribute(String id, ChatColor color, AttributeSource source, Function valueFormatter) { this.id = id; + this.name = new TranslatableText(TranslatableText.Type.ATTRIBUTE + "-" + id); this.color = color; this.source = source; diff --git a/src/main/java/me/zenox/evocraft/attribute/AttributeModifier.java b/src/main/java/me/zenox/evocraft/attribute/AttributeModifier.java index f2fdbe5..11d6cc5 100644 --- a/src/main/java/me/zenox/evocraft/attribute/AttributeModifier.java +++ b/src/main/java/me/zenox/evocraft/attribute/AttributeModifier.java @@ -1,6 +1,6 @@ package me.zenox.evocraft.attribute; -import com.archyx.aureliumskills.modifier.StatModifier; +import dev.aurelium.auraskills.api.stat.StatModifier; import me.zenox.evocraft.Slot; import me.zenox.evocraft.attribute.types.AureliumAttribute; import me.zenox.evocraft.attribute.types.MinecraftAttribute; @@ -50,10 +50,10 @@ public static AttributeModifier of(org.bukkit.attribute.Attribute attribute, org public static AttributeModifier of(StatModifier modifier){ try { - return new AttributeModifier(modifier.getName(), UUID.randomUUID(), + return new AttributeModifier(modifier.name(), UUID.randomUUID(), ((Attribute) Attribute.attributeRegistry.stream() - .filter(attribute1 -> attribute1 instanceof AureliumAttribute && ((AureliumAttribute) attribute1).getStat() == modifier.getStat()) - .toArray()[0]), modifier.getValue(), Operation.ADD_NUMBER, modifier.getName().contains("item") && !modifier.getName().contains("armor") ? Slot.MAIN_HAND : Slot.ARMOR); + .filter(attribute1 -> attribute1 instanceof AureliumAttribute && ((AureliumAttribute) attribute1).getStat() == modifier.stat()) + .toArray()[0]), modifier.value(), Operation.ADD_NUMBER, modifier.name().contains("item") && !modifier.name().contains("armor") ? Slot.MAIN_HAND : Slot.ARMOR); } catch (IndexOutOfBoundsException e){ throw new IllegalArgumentException("AttributeModifier " + modifier + " was"); } diff --git a/src/main/java/me/zenox/evocraft/attribute/AttributeRegistry.java b/src/main/java/me/zenox/evocraft/attribute/AttributeRegistry.java index 838c725..b315407 100644 --- a/src/main/java/me/zenox/evocraft/attribute/AttributeRegistry.java +++ b/src/main/java/me/zenox/evocraft/attribute/AttributeRegistry.java @@ -1,6 +1,6 @@ package me.zenox.evocraft.attribute; -import com.archyx.aureliumskills.stats.Stats; +import dev.aurelium.auraskills.api.stat.Stats; import me.zenox.evocraft.attribute.types.AureliumAttribute; import me.zenox.evocraft.attribute.types.MinecraftAttribute; import me.zenox.evocraft.util.Util; @@ -25,6 +25,8 @@ public class AttributeRegistry { public static final Attribute AS_LUCK = new AureliumAttribute("as-luck", ChatColor.GREEN, Stats.LUCK); public static final Attribute WISDOM = new AureliumAttribute("as-wisdom", ChatColor.BLUE, Stats.WISDOM); public static final Attribute TOUGHNESS = new AureliumAttribute("as-toughness", ChatColor.DARK_PURPLE, Stats.TOUGHNESS); + public static final Attribute CRIT_CHANCE = new AureliumAttribute("as-crit_chance", ChatColor.GOLD, Stats.CRIT_CHANCE); + public static final Attribute CRIT_DAMAGE = new AureliumAttribute("as-crit_damage", ChatColor.GOLD, Stats.CRIT_DAMAGE); public static void registerAttributes(){ Util.logToConsole(ChatColor.WHITE + "Registering " + ChatColor.GOLD + Attribute.attributeRegistry.size() + ChatColor.WHITE + " attributes"); diff --git a/src/main/java/me/zenox/evocraft/attribute/types/AureliumAttribute.java b/src/main/java/me/zenox/evocraft/attribute/types/AureliumAttribute.java index a906061..a45c078 100644 --- a/src/main/java/me/zenox/evocraft/attribute/types/AureliumAttribute.java +++ b/src/main/java/me/zenox/evocraft/attribute/types/AureliumAttribute.java @@ -1,13 +1,13 @@ package me.zenox.evocraft.attribute.types; -import com.archyx.aureliumskills.api.AureliumAPI; -import com.archyx.aureliumskills.modifier.ModifierType; -import com.archyx.aureliumskills.modifier.StatModifier; -import com.archyx.aureliumskills.stats.Stat; +import dev.aurelium.auraskills.api.AuraSkillsBukkit; +import dev.aurelium.auraskills.api.item.ItemManager; +import dev.aurelium.auraskills.api.item.ModifierType; +import dev.aurelium.auraskills.api.stat.Stat; +import dev.aurelium.auraskills.api.stat.StatModifier; import me.zenox.evocraft.Slot; import me.zenox.evocraft.attribute.Attribute; import me.zenox.evocraft.attribute.AttributeModifier; -import me.zenox.evocraft.util.Util; import org.bukkit.ChatColor; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -17,8 +17,12 @@ public class AureliumAttribute extends Attribute { + private static final ItemManager itemManager = AuraSkillsBukkit.get().getItemManager(); + private final Stat stat; + + public AureliumAttribute(String id, ChatColor color, Stat stat) { this(id, color, stat, (value) -> (value > 0 ? "+" : "") + value); } @@ -31,12 +35,12 @@ public AureliumAttribute(String id, ChatColor color, Stat stat, Function stat.equals(statModifier.getStat())) - .mapToDouble(StatModifier::getValue) + .filter(statModifier -> stat.equals(statModifier.stat())) + .mapToDouble(StatModifier::value) .sum(); if (modifier.getOperation().equals(org.bukkit.attribute.AttributeModifier.Operation.ADD_SCALAR)){ @@ -47,15 +51,15 @@ public ItemStack apply(ItemStack item, @NotNull AttributeModifier modifier) { // Returns an armor modifier if the item's type is a valid armor type, otherwise adds an item modifier if(List.of(Slot.HEAD, Slot.CHEST, Slot.LEGS, Slot.FEET, Slot.ARMOR).contains(modifier.getSlot())){ - return AureliumAPI.addArmorModifier(item, stat, curValue, false); + return itemManager.addStatModifier(item, ModifierType.ARMOR, stat, curValue, false); } else { - return AureliumAPI.addItemModifier(item, stat, curValue, false); + return itemManager.addStatModifier(item, ModifierType.ITEM, stat, curValue, false); } } @Override public ItemStack remove(ItemStack item, @NotNull AttributeModifier modifier) { - return Util.removeAureliumModifier(item, List.of(Slot.HEAD, Slot.CHEST, Slot.LEGS, Slot.FEET, Slot.ARMOR) + return itemManager.removeStatModifier(item, List.of(Slot.HEAD, Slot.CHEST, Slot.LEGS, Slot.FEET, Slot.ARMOR) .contains(modifier.getSlot()) ? ModifierType.ARMOR : ModifierType.ITEM, stat); } diff --git a/src/main/java/me/zenox/evocraft/command/Command.java b/src/main/java/me/zenox/evocraft/command/Command.java index 07f1319..d33084e 100644 --- a/src/main/java/me/zenox/evocraft/command/Command.java +++ b/src/main/java/me/zenox/evocraft/command/Command.java @@ -2,284 +2,307 @@ import com.google.common.primitives.Ints; import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.data.PlayerData; +import me.zenox.evocraft.data.PlayerDataManager; import me.zenox.evocraft.enchant.ComplexEnchantment; +import me.zenox.evocraft.gameclass.GameClass; +import me.zenox.evocraft.gameclass.tree.Path; import me.zenox.evocraft.item.ComplexItem; import me.zenox.evocraft.item.ComplexItemMeta; import me.zenox.evocraft.item.ComplexItemStack; -import me.zenox.evocraft.item.ItemRegistry; import me.zenox.evocraft.loot.LootTable; import me.zenox.evocraft.loot.LootTableRegistry; -import me.zenox.evocraft.story.Chapter; -import me.zenox.evocraft.story.ChapterManager; import me.zenox.evocraft.util.Util; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import xyz.xenondevs.invui.window.Window; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; public class Command implements CommandExecutor, TabCompleter { private final EvoCraft plugin; + private final Map> subcommands = new HashMap<>(); public Command(EvoCraft plugin) { this.plugin = plugin; + + // Register subcommands + subcommands.put("give", this::handleGive); + subcommands.put("loottable", this::handleLootTable); + subcommands.put("dropitematplayer", this::handleDropItemAtPlayer); + subcommands.put("droploottable", this::handleDropLootTable); + subcommands.put("enchant", this::handleEnchant); + subcommands.put("reload", this::handleReload); + subcommands.put("model", this::handleModel); + subcommands.put("class", this::handleClass); + subcommands.put("progresspath", this::handleProgressPath); + plugin.getCommand("evocraft").setExecutor(this); plugin.getCommand("evocraft").setTabCompleter(this); } @Override public boolean onCommand(CommandSender sender, org.bukkit.command.Command command, String label, String[] args) { - if (args.length == 0) { - Util.sendMessage(sender, "EvoCraft Help Page."); + Util.sendMessage(sender, "EvoCraft Help Page. Available commands: " + String.join(", ", subcommands.keySet())); return true; } - switch (args[0]) { - case "give" -> { - if (args.length < 2 || sender.getServer().getPlayer(args[1]) == null) { - Util.sendMessage(sender, "Please specify a valid user to give an item."); - return true; - } - Player p = (Player) sender; - Player givento = sender.getServer().getPlayer(args[1]); - if (args.length < 3) { - Util.sendMessage(p, "Please specify a item to give."); - return true; - } - ComplexItem itemtype = ItemRegistry.byId(args[2]); - if (itemtype == null) { - Util.sendMessage(p, "This item could not be found!"); - } else { - Object amount; - if (args.length >= 4) { - amount = Ints.tryParse(args[3]); - if (amount == null) { - Util.sendMessage(p, args[3] + " is not a valid integer! Please specify an integer for argument ."); - return true; - } - } else { - amount = 1; - } + Consumer subcommand = subcommands.get(args[0].toLowerCase()); + if (subcommand == null) { + Util.sendMessage(sender, "Unknown subcommand. Type /evocraft for help."); + return true; + } - givento.getInventory().addItem(new ComplexItemStack(itemtype, (int) amount).getItem()); - Util.sendMessage(p, "You gave " + givento.getDisplayName() + " x" + amount + " [" + itemtype.getDisplayName() + ChatColor.GOLD + "]"); - } - return true; - } - case "loottable" -> { - if (args.length < 2 || sender.getServer().getPlayer(args[1]) == null) { - Util.sendMessage(sender, "Please specify a valid user to give a loottable for."); - return true; - } - if (args.length < 3) { - Util.sendMessage(sender, "Please specify a valid loottable."); - return true; - } - int threatlevel; - if (args.length < 4 || Ints.tryParse(args[3]) == null) { - threatlevel = 1; - } else { - threatlevel = Ints.tryParse(args[3]); - } - for (LootTable lootTable : LootTableRegistry.lootTableList) { - if (args[2].equalsIgnoreCase(lootTable.getId())) { - lootTable.openLootGUI(sender.getServer().getPlayer(args[1]), threatlevel); - return true; - } - } - } - case "dropitematplayer" -> { - if (args.length < 2 || sender.getServer().getPlayer(args[1]) == null) { - Util.sendMessage(sender, "Please specify a valid user to drop an item at."); - return true; - } - Player dropgivento = sender.getServer().getPlayer(args[1]); - if (args.length < 3) { - Util.sendMessage(sender, "Please specify a item to drop."); - return true; - } - ComplexItem itemtypetodrop = ItemRegistry.byId(args[2]); - if (itemtypetodrop == null) { - Util.sendMessage(sender, "This item could not be found!"); - } else { - Object amount; - if (args.length >= 4) { - amount = Ints.tryParse(args[3]); - if (amount == null) { - Util.sendMessage(sender, args[3] + " is not a valid integer! Please specify an integer for argument ."); - return true; - } - } else { - amount = 1; - } + CommandContext context = new CommandContext(sender, args); + try { + subcommand.accept(context); + } catch (IllegalArgumentException e) { + Util.sendMessage(sender, ChatColor.RED + "Error: " + e.getMessage()); + } + return true; + } - dropgivento.getWorld().dropItemNaturally(dropgivento.getLocation(), new ComplexItemStack(itemtypetodrop, (int) amount).getItem()); - Util.sendMessage(sender, "You gave " + dropgivento.getDisplayName() + " x" + amount + " [" + itemtypetodrop.getDisplayName() + ChatColor.GOLD + "]"); - } - } - case "droploottable" -> { - if (args.length < 2 || sender.getServer().getEntity(UUID.fromString(args[1])) == null) { - Util.sendMessage(sender, "Please specify a valid entity to give a loot table for."); - return true; - } - if (args.length < 3) { - Util.sendMessage(sender, "Please specify a valid loot table."); - return true; - } - for (LootTable lootTable : LootTableRegistry.lootTableList) { - if (args[2].equalsIgnoreCase(lootTable.getId())) { - lootTable.dropLoot(sender.getServer().getEntity(UUID.fromString(args[1])).getLocation(), 1); - return true; - } - } - return false; - } - case "enchant" -> { - if (args.length < 2 || sender.getServer().getPlayer(args[1]) == null) { - Util.sendMessage(sender, "Please specify a valid user to give an item."); - return true; - } - if (args.length < 3) { - Util.sendMessage(sender, "Please specify a item to give."); - return true; - } - Player enchanted = sender.getServer().getPlayer(args[1]); - ComplexEnchantment enchant = ComplexEnchantment.byId(args[2]); - if (enchant == null) { - Util.sendMessage(sender, "Enchantment " + ChatColor.WHITE + args[2] + " doesn't exist."); - } else { - Object level; - if (args.length >= 4) { - level = Ints.tryParse(args[3]); - if (level == null) { - Util.sendMessage(sender, args[3] + " is not a valid integer! Please specify an integer for argument ."); - return true; - } - } else { - level = 1; - } + private void handleGive(CommandContext context) { + Player giver = context.requirePlayer(); + Player recipient = context.requirePlayerArgument(1, "Please specify a valid player to give an item."); + String itemId = context.requireStringArgument(2, "Please specify an item to give."); + ComplexItem item = ComplexItem.itemRegistry.get(itemId); + if (item == null) throw new IllegalArgumentException("Item not found: " + itemId); - ComplexItemMeta meta = ComplexItemStack.of(enchanted.getInventory().getItemInMainHand()).getComplexMeta(); - if(((int) level) > 0) meta.addEnchantment(enchant, (Integer) level); - else meta.removeEnchantment(enchant); - Util.sendMessage(sender, "You enchanted " + enchanted.getDisplayName() + " with " + ChatColor.WHITE + enchant.getName() + " " + level); - } - return true; - } - case "reload" -> { - plugin.reload(); - Util.sendMessage(sender, ChatColor.WHITE + "EvoCraft " + ChatColor.GREEN + "v" + plugin.getDescription().getVersion() + ChatColor.WHITE + " has been reloaded."); - return true; - } - case "model" -> { - ItemStack item = ((Player) sender).getEquipment().getItemInMainHand(); - if(item.getType() == Material.AIR) { - Util.sendMessage(sender, ChatColor.WHITE + "This item has no CustomModelData (that is created by EvoCraft)"); - return true; - } - Util.sendMessage(sender, ChatColor.WHITE + "The CustomModelData of " + item.getItemMeta().getDisplayName() + ChatColor.WHITE + " is " + ComplexItemStack.of(item).getComplexItem().getCustomModelData()); - return true; - } - case "removechapterdata" -> { - if (sender instanceof Player){ - ((Player) sender).getPersistentDataContainer().remove(ChapterManager.CHAPTER_KEY); - Util.sendMessage(sender, "All chapter data has been removed."); - } - else { - Util.sendMessage(sender, "You must be a player to use this command!"); - } - } - case "removemetadata" -> { - if (sender instanceof Player){ - sender.getServer().getPlayer(args[1]).removeMetadata("hasStarted", EvoCraft.getPlugin()); - Util.sendMessage(sender, "All chapter data has been removed."); - } - else { - Util.sendMessage(sender, "You must be a player to use this command!"); - } - } - case "setchapter" -> { - // Set the chapter given the player and the chapter's id - if (args.length < 2 || sender.getServer().getPlayer(args[1]) == null) { - Util.sendMessage(sender, "Please specify a valid user to set the chapter of."); - return true; - } - if (args.length < 3) { - Util.sendMessage(sender, "Please specify a valid chapter."); - return true; - } - Player player = sender.getServer().getPlayer(args[1]); - Chapter chapter = EvoCraft.getChapterManager().getChapter(Ints.tryParse(args[2])); - if (chapter == null) { - Util.sendMessage(sender, "This chapter does not exist!"); - return true; - } - EvoCraft.getChapterManager().setChapter(player, chapter); - return true; - } - default -> Util.sendMessage(sender, "EvoCraft Help Page."); + int amount = context.optionalIntArgument(3, 1); + recipient.getInventory().addItem(new ComplexItemStack(item, amount).getItem()); + Util.sendMessage(giver, "Gave " + recipient.getDisplayName() + " x" + amount + " [" + item.getDisplayName() + "]"); + } + + private void handleLootTable(CommandContext context) { + Player player = context.requirePlayer(); + Player recipient = context.requirePlayerArgument(1, "Please specify a valid player."); + String lootTableId = context.requireStringArgument(2, "Please specify a valid loot table."); + int threatLevel = context.optionalIntArgument(3, 1); + + LootTable lootTable = LootTableRegistry.lootTableList.stream() + .filter(lt -> lootTableId.equalsIgnoreCase(lt.getId())) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Loot table not found: " + lootTableId)); + + lootTable.openLootGUI(recipient, threatLevel); + Util.sendMessage(player, "Opened loot table " + lootTableId + " for " + recipient.getDisplayName()); + } + + private void handleDropItemAtPlayer(CommandContext context) { + Player player = context.requirePlayer(); + Player target = context.requirePlayerArgument(1, "Please specify a valid player."); + String itemId = context.requireStringArgument(2, "Please specify an item to drop."); + ComplexItem item = ComplexItem.itemRegistry.get(itemId); + if (item == null) throw new IllegalArgumentException("Item not found: " + itemId); + + int amount = context.optionalIntArgument(3, 1); + target.getWorld().dropItemNaturally(target.getLocation(), new ComplexItemStack(item, amount).getItem()); + Util.sendMessage(player, "Dropped x" + amount + " [" + item.getDisplayName() + "] at " + target.getDisplayName()); + } + + private void handleDropLootTable(CommandContext context) { + String entityUUID = context.requireStringArgument(1, "Please specify a valid entity UUID."); + String lootTableId = context.requireStringArgument(2, "Please specify a valid loot table."); + int amount = context.optionalIntArgument(3, 1); + + LootTable lootTable = LootTableRegistry.lootTableList.stream() + .filter(lt -> lootTableId.equalsIgnoreCase(lt.getId())) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Loot table not found: " + lootTableId)); + + lootTable.dropLoot(context.getSender().getServer().getEntity(UUID.fromString(entityUUID)).getLocation(), 1); + } + + private void handleReload(CommandContext context) { + plugin.reload(); + Util.sendMessage(context.getSender(), ChatColor.GREEN + "EvoCraft has been reloaded."); + } + + private void handleProgressPath(CommandContext context) { + Player player = context.requirePlayer(); + String pathId = context.requireStringArgument(1, "Please specify a valid path."); + int level = context.optionalIntArgument(2, -1); + + PlayerData data = PlayerDataManager.getInstance().getPlayerData(player.getUniqueId()); + Path path = data.getPlayerClass().tree().path(pathId); + if (path == null) throw new IllegalArgumentException("Path not found: " + pathId); + + if (level == -1) { + data.progressPath(path); + Util.sendMessage(player, "Progressed on path " + path.getId() + " to level " + data.getPathLevel(path) + "."); + } else { + data.setPathLevel(path, level); + Util.sendMessage(player, "Set path " + path.getId() + " to level " + level + "."); } - return true; } - final List arguments = new ArrayList<>(); - final List items = new ArrayList<>(); + private void handleEnchant(CommandContext context) { + Player player = context.requirePlayer(); + Player target = context.requirePlayerArgument(1, "Please specify a valid player."); + String enchantmentId = context.requireStringArgument(2, "Please specify an enchantment."); + ComplexEnchantment enchantment = ComplexEnchantment.byId(enchantmentId); + if (enchantment == null) throw new IllegalArgumentException("Enchantment not found: " + enchantmentId); - @Override - public List onTabComplete(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) { - if (arguments.isEmpty()) { - arguments.add("give"); - arguments.add("loottable"); - arguments.add("droploottable"); - arguments.add("dropitematplayer"); - arguments.add("enchant"); - arguments.add("reload"); - arguments.add("removechapterdata"); + int level = context.optionalIntArgument(3, 1); + ItemStack item = target.getInventory().getItemInMainHand(); + if (item == null || item.getType().isAir()) throw new IllegalArgumentException("The target's main hand is empty."); + + ComplexItemMeta meta = ComplexItemStack.of(item).getComplexMeta(); + if (level > 0) { + meta.addEnchantment(enchantment, level); + } else { + meta.removeEnchantment(enchantment); } + Util.sendMessage(player, "Enchanted " + target.getDisplayName() + "'s item with " + enchantment.getName() + " (level " + level + ")."); + } - if (items.isEmpty()) { - for (ComplexItem item : ComplexItem.itemRegistry) { - items.add(item.getId()); - } + private void handleModel(CommandContext context) { + Player player = context.requirePlayer(); + ItemStack item = player.getEquipment().getItemInMainHand(); + if (item.getType().isAir()) { + Util.sendMessage(player, "This item has no CustomModelData (that is created by EvoCraft)."); + return; } - List results = new ArrayList<>(); + ComplexItem complexItem = ComplexItem.of(item); + if (complexItem == null) { + Util.sendMessage(player, "This item is not a valid EvoCraft item."); + return; + } + + Util.sendMessage(player, "The CustomModelData of " + item.getItemMeta().getDisplayName() + " is " + complexItem.getCustomModelData()); + } + + private void handleClass(CommandContext context) { + Player player = context.requirePlayer(); + Window.single() + .setViewer(player) + .setTitle("Class Selection") + .setGui(GameClass.getGui()) + .setCloseable(true) + .build() + .open(); + } + + + + // Additional handlers... + + @Override + public List onTabComplete(CommandSender sender, org.bukkit.command.Command command, String label, String[] args) { if (args.length == 1) { - for (String a : arguments) { - if (a.toLowerCase().startsWith(args[0].toLowerCase())) { - results.add(a); + return subcommands.keySet().stream() + .filter(cmd -> cmd.startsWith(args[0].toLowerCase())) + .sorted() + .collect(Collectors.toList()); + } + + if (args.length >= 2) { + switch (args[0].toLowerCase()) { + case "give", "dropitematplayer" -> { + if (args.length == 2) { + // Suggest player names + return getOnlinePlayers(sender).stream() + .filter(name -> name.toLowerCase().startsWith(args[1].toLowerCase())) + .sorted() + .collect(Collectors.toList()); + } else if (args.length == 3) { + // Suggest item IDs + return ComplexItem.itemRegistry.keySet().stream() + .filter(item -> item.toLowerCase().startsWith(args[2].toLowerCase())) + .sorted() + .collect(Collectors.toList()); + } } - } - return results; - } else if (args.length == 3 && args[0].equalsIgnoreCase("give")) { - for (String b : items) { - if (b.toLowerCase().startsWith(args[2].toLowerCase())) { - results.add(b); + case "loottable", "droploottable" -> { + if (args.length == 2) { + // Suggest player or entity UUIDs + return getOnlinePlayers(sender).stream() + .filter(name -> name.toLowerCase().startsWith(args[1].toLowerCase())) + .sorted() + .collect(Collectors.toList()); + } else if (args.length == 3) { + // Suggest loot table IDs + return LootTableRegistry.lootTableList.stream() + .map(LootTable::getId) + .filter(id -> id.toLowerCase().startsWith(args[2].toLowerCase())) + .sorted() + .collect(Collectors.toList()); + } } - } - return results; - } else if (args.length == 3 && args[0].equalsIgnoreCase("enchant")) { - for (ComplexEnchantment b : ComplexEnchantment.getRegisteredEnchants()) { - if (b.getId().toLowerCase().startsWith(args[2].toLowerCase())) { - results.add(b.getId()); + case "progresspath" -> { + if (args.length == 2 && sender instanceof Player) { + // Suggest paths + Player player = (Player) sender; + GameClass gameClass = PlayerDataManager.getInstance() + .getPlayerData(player.getUniqueId()).getPlayerClass(); + return gameClass.tree().paths().stream() + .map(Path::getId) + .filter(path -> path.toLowerCase().startsWith(args[1].toLowerCase())) + .sorted() + .collect(Collectors.toList()); + } } } - return results; - } else if (args.length == 4 && args[0].equalsIgnoreCase("enchant")) { - results.add(""); - return results; - } else if (args.length == 4 && args[0].equalsIgnoreCase("give")) { - results.add(""); - return results; } - return null; + + return Collections.emptyList(); + } + + private List getOnlinePlayers(CommandSender sender) { + return sender.getServer().getOnlinePlayers().stream() + .map(Player::getName) + .collect(Collectors.toList()); + } + + private static class CommandContext { + private final CommandSender sender; + private final String[] args; + + public CommandContext(CommandSender sender, String[] args) { + this.sender = sender; + this.args = args; + } + + public CommandSender getSender() { + return sender; + } + + public Player requirePlayer() { + if (!(sender instanceof Player)) throw new IllegalArgumentException("This command can only be used by a player."); + return (Player) sender; + } + + public Player requirePlayerArgument(int index, String errorMessage) { + if (args.length <= index) throw new IllegalArgumentException(errorMessage); + Player player = sender.getServer().getPlayer(args[index]); + if (player == null) throw new IllegalArgumentException("Player not found: " + args[index]); + return player; + } + + public String requireStringArgument(int index, String errorMessage) { + if (args.length <= index) throw new IllegalArgumentException(errorMessage); + return args[index]; + } + + public int optionalIntArgument(int index, int defaultValue) { + if (args.length <= index) return defaultValue; + Integer value = Ints.tryParse(args[index]); + if (value == null) throw new IllegalArgumentException("Invalid number: " + args[index]); + return value; + } + + public org.bukkit.Server requireServer() { + return sender.getServer(); + } } -} +} \ No newline at end of file diff --git a/src/main/java/me/zenox/evocraft/data/LanguageLoader.java b/src/main/java/me/zenox/evocraft/data/LanguageLoader.java index 5115d0e..6705ce1 100644 --- a/src/main/java/me/zenox/evocraft/data/LanguageLoader.java +++ b/src/main/java/me/zenox/evocraft/data/LanguageLoader.java @@ -25,6 +25,7 @@ public LanguageLoader(EvoCraft plugin) { languageDirectory.mkdir(); try { InputStream stream = plugin.getResource("languages/en_US.yml"); + assert stream != null; FileUtils.copyInputStreamToFile(stream, defaultLanguageFile); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/me/zenox/evocraft/data/PlayerData.java b/src/main/java/me/zenox/evocraft/data/PlayerData.java new file mode 100644 index 0000000..c62c2e6 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/data/PlayerData.java @@ -0,0 +1,69 @@ +package me.zenox.evocraft.data; + +import me.zenox.evocraft.gameclass.GameClass; +import me.zenox.evocraft.gameclass.tree.Path; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PlayerData { + + private final UUID uuid; + + private GameClass playerClass; + private final Map pathLevelMap; + + public PlayerData(UUID uuid, GameClass playerClass, Map pathLevelMap) { + this.uuid = uuid; + this.playerClass = playerClass; + this.pathLevelMap = pathLevelMap; + } + + public PlayerData(UUID uuid, GameClass playerClass) { + this(uuid, playerClass, new HashMap<>()); + playerClass.tree().paths().forEach(path -> pathLevelMap.put(path, 0)); + } + + public UUID getUuid() { + return uuid; + } + + // Getter and Setter for playerClass + public GameClass getPlayerClass() { + return playerClass; + } + + public void setPlayerClass(GameClass playerClass) { + this.playerClass = playerClass; + } + + public Map getPathLevelMap() { + return pathLevelMap; + } + + // Method to get ability level + public int getPathLevel(Path path) { + return pathLevelMap.getOrDefault(path, -1); + } + + // Method to set ability level + public void setPathLevel(Path path, int level) { + pathLevelMap.put(path, level); + } + + // Progress the level of a specific ability + public void progressPath(Path path) { + int currentLevel = getPathLevel(path); + if (getPathLevel(path) < path.getMaxLevel()) + setPathLevel(path, currentLevel + 1); + else throw new IllegalArgumentException("Ability " + path.getId() + " is already at max level!"); + } + + // Display all abilities and their levels + public void displayAbilities() { + for (Path path : pathLevelMap.keySet()) { + System.out.println(path.getId() + ": Level " + pathLevelMap.get(path)); + } + } +} \ No newline at end of file diff --git a/src/main/java/me/zenox/evocraft/data/PlayerDataManager.java b/src/main/java/me/zenox/evocraft/data/PlayerDataManager.java new file mode 100644 index 0000000..0f70aff --- /dev/null +++ b/src/main/java/me/zenox/evocraft/data/PlayerDataManager.java @@ -0,0 +1,141 @@ +package me.zenox.evocraft.data; + +import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.gameclass.GameClass; +import me.zenox.evocraft.gameclass.tree.Path; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Unmodifiable; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class PlayerDataManager { + private final File playerDataFile; + private final FileConfiguration playerDataConfig; + + private final Map loadedPlayerData = new ConcurrentHashMap<>(); + + private static PlayerDataManager instance; + + public PlayerDataManager() { + if (instance != null) throw new IllegalStateException("PlayerDataManager already initialized"); + instance = this; + + playerDataFile = new File(EvoCraft.getPlugin().getDataFolder(), "playerdata.yml"); + if (!playerDataFile.exists()) { + try { + playerDataFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + playerDataConfig = YamlConfiguration.loadConfiguration(playerDataFile); + + startAutoSave(); + } + + private void startAutoSave() { + long delay = 20L*60L*EvoCraft.getPlugin().getConfig().getLong("autosave-minutes"); + + Bukkit.getScheduler().runTaskTimer(EvoCraft.getPlugin(), this::saveAllPlayerData, delay, delay); + } + + private PlayerData createPlayerData(UUID uuid) { + PlayerData newPlayerData = new PlayerData(uuid, GameClass.NONE, new HashMap<>()); + if (newPlayerData.getPlayerClass().tree() != null) + newPlayerData.getPlayerClass().tree().paths().forEach(path -> newPlayerData.setPathLevel(path, -1)); + + savePlayerDataImmediately(newPlayerData); + loadedPlayerData.put(uuid, newPlayerData); + + return newPlayerData; + } + + public PlayerData getPlayerData(UUID uuid) { + PlayerData data = loadedPlayerData.get(uuid); + if(data == null) { + data = loadPlayerData(uuid); + if(data == null) { + data = createPlayerData(uuid); + } + loadedPlayerData.put(uuid, data); + } + return data; + } + + public void saveAllPlayerData() { + loadedPlayerData.values().forEach(this::savePlayerData); + } + + // Call this method when a critical change has occurred + public void savePlayerDataImmediately(PlayerData playerData) { + savePlayerData(playerData); + loadedPlayerData.put(playerData.getUuid(), playerData); // Update the in-memory cache + } + + // Call this method during server shutdown + public void shutdown() { + saveAllPlayerData(); + } + + public void savePlayerData(PlayerData playerData) { + // Serialize PlayerData object to YAML + // You will need to implement serialization for your complex types + playerDataConfig.createSection(playerData.getUuid().toString(), serializePlayerData(playerData)); + try { + playerDataConfig.save(playerDataFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public PlayerData loadPlayerData(@NotNull UUID uuid) { + // Deserialize from YAML to PlayerData + // You will need to implement deserialization for your complex types + ConfigurationSection section = playerDataConfig.getConfigurationSection(uuid.toString()); + if (section == null) return null; + return deserializePlayerData(section); + } + + private @NotNull @Unmodifiable Map serializePlayerData(@NotNull PlayerData playerData) { + Map pathMap = new HashMap<>(); + for (Map.Entry entry: playerData.getPathLevelMap().entrySet()) + pathMap.put(entry.getKey().getId(), entry.getValue()); + return Map.of( + "data_version", 0, + "class", playerData.getPlayerClass().id(), + "paths", pathMap + ); + } + + private PlayerData deserializePlayerData(@NotNull ConfigurationSection section) { + return switch (((int) section.get("data_version", 0))) { + case 0 -> new PlayerData( + UUID.fromString(section.getName()), + GameClass.getFromID(section.getString("class")), + deserializePathMap(section.getConfigurationSection("paths")) + ); + default -> throw new IllegalArgumentException("Invalid data version"); + }; + } + + private @NotNull Map deserializePathMap(@NotNull ConfigurationSection paths) { + Map pathMap = new HashMap<>(); + for (String key: paths.getKeys(false)){ + pathMap.put(Path.getFromID(key), paths.getInt(key)); + } + return pathMap; + } + + public static PlayerDataManager getInstance() { + return instance; + } +} diff --git a/src/main/java/me/zenox/evocraft/data/TranslatableText.java b/src/main/java/me/zenox/evocraft/data/TranslatableText.java index 4e60ec3..0c18b86 100644 --- a/src/main/java/me/zenox/evocraft/data/TranslatableText.java +++ b/src/main/java/me/zenox/evocraft/data/TranslatableText.java @@ -26,7 +26,10 @@ public enum Type { ITEM_NAME("item-name"), ITEM_LORE("item-lore"), ABILITY_NAME("ability-name"), ABILITY_LORE("ability-lore"), COMMAND("cmd"), MISC_MSG("msg"), ENCHANT_NAME("enchant-name"), - ATTRIBUTE("attribute"), GUI("gui"); + ATTRIBUTE("attribute"), GUI("gui"), + CLASS_NAME("class-name"), CLASS_DESC("class-desc"), + SKILL_NAME("skill-name"), SKILL_DESC("skill-desc"), + MODIFIER_NAME("modifier-name"), MODIFIER_LORE("modifier-lore"); private final String key; diff --git a/src/main/java/me/zenox/evocraft/events/InventoryListener.java b/src/main/java/me/zenox/evocraft/events/InventoryListener.java index 61886a4..b11bde7 100644 --- a/src/main/java/me/zenox/evocraft/events/InventoryListener.java +++ b/src/main/java/me/zenox/evocraft/events/InventoryListener.java @@ -11,6 +11,7 @@ import org.bukkit.event.entity.EntityDropItemEvent; import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCreativeEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.inventory.ItemStack; @@ -32,38 +33,45 @@ public void inventoryOpenEvent(InventoryOpenEvent event) { ArrayList contents = new ArrayList<>(); contents.addAll(Arrays.asList(event.getPlayer().getInventory().getContents())); contents.addAll(Arrays.asList(event.getPlayer().getInventory().getArmorContents())); - updateInventory(contents); + updateItems(contents); } @EventHandler(priority = EventPriority.HIGHEST) public void inventoryInteractEvent(InventoryClickEvent event) { ArrayList contents = new ArrayList<>(); contents.add(event.getCurrentItem()); - if(!event.isCancelled()) updateInventory(contents); + contents.add(event.getCursor()); + if(!event.isCancelled()) updateItems(contents); } @EventHandler public void inventoryPickupEvent(EntityPickupItemEvent event) { ArrayList contents = new ArrayList<>(); contents.add(event.getItem().getItemStack()); - updateInventory(contents); + updateItems(contents); } @EventHandler public void itemDropEvent(EntityDropItemEvent event){ ArrayList contents = new ArrayList<>(); contents.add(event.getItemDrop().getItemStack()); - updateInventory(contents); + updateItems(contents); } @EventHandler public void itemDropEvent(BlockDropItemEvent event){ + ArrayList contents = new ArrayList<>(event.getItems().stream().map(Item::getItemStack).toList()); + updateItems(contents); + } + + @EventHandler + public void creativeEvent(InventoryCreativeEvent event) { ArrayList contents = new ArrayList<>(); - contents.addAll(event.getItems().stream().map(Item::getItemStack).toList()); - updateInventory(contents); + contents.add(event.getCursor()); + updateItems(contents); } - private void updateInventory(List contents) { + private void updateItems(List contents) { contents.removeIf(Objects::isNull); // Update ComplexItems diff --git a/src/main/java/me/zenox/evocraft/events/OtherEvent.java b/src/main/java/me/zenox/evocraft/events/OtherEvent.java index 4f4d2ba..978acd6 100644 --- a/src/main/java/me/zenox/evocraft/events/OtherEvent.java +++ b/src/main/java/me/zenox/evocraft/events/OtherEvent.java @@ -1,10 +1,10 @@ package me.zenox.evocraft.events; import com.destroystokyo.paper.event.inventory.PrepareResultEvent; -import de.studiocode.invui.window.impl.single.SimpleWindow; import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.abilities.ClassAbility; import me.zenox.evocraft.enchant.ComplexEnchantment; -import me.zenox.evocraft.gui.EnchantingGUI; +import me.zenox.evocraft.gui.EnchantingGui; import me.zenox.evocraft.item.ComplexItemMeta; import me.zenox.evocraft.item.ComplexItemStack; import me.zenox.evocraft.item.VanillaItem; @@ -29,6 +29,7 @@ import org.bukkit.metadata.MetadataValue; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; +import xyz.xenondevs.invui.window.Window; import java.util.HashMap; import java.util.List; @@ -48,13 +49,17 @@ public OtherEvent(EvoCraft plugin) { @EventHandler public void tileEntityInteract(PlayerInteractEvent e){ if(e.getAction() == Action.RIGHT_CLICK_BLOCK){ - switch(e.getClickedBlock().getType()){ - case ENCHANTING_TABLE -> new SimpleWindow(e.getPlayer(), "Enchantment Table", EnchantingGUI.getGui(e.getPlayer(), e.getClickedBlock()), true, true).show(); - default -> { - return; - } + if (Objects.requireNonNull(e.getClickedBlock()).getType() == Material.ENCHANTING_TABLE) { + e.setCancelled(true); + Window.single() + .setViewer(e.getPlayer()) + .setTitle("Enchantment Table") + .setGui(EnchantingGui.getGui(e.getPlayer(), e.getClickedBlock())) + .setCloseable(true) + .build() + .open(); } - e.setCancelled(true); + } } @@ -77,21 +82,38 @@ public void projectileExplode(EntityExplodeEvent e) { } } } + @EventHandler + public void damageEventCounterstrike(EntityDamageByEntityEvent entityDamageByEntityEvent){ + if(!(entityDamageByEntityEvent.getEntity() instanceof Player)) return; + Player player = (Player) entityDamageByEntityEvent.getEntity(); + if(ClassAbility.counterStrikeActive.contains(player)) { + if (((entityDamageByEntityEvent.getDamager() instanceof LivingEntity))) { + ((LivingEntity) entityDamageByEntityEvent.getDamager()).damage(entityDamageByEntityEvent.getDamage()/2); + } + entityDamageByEntityEvent.setCancelled(true); + ClassAbility.counterStrikeActive.remove(player); + player.removePotionEffect(PotionEffectType.SLOW); + player.removePotionEffect(PotionEffectType.SLOW_FALLING); + player.removePotionEffect(PotionEffectType.WEAKNESS); + } + } @EventHandler - public void projectileCollide(ProjectileHitEvent e){ + public void projectileCollide(ProjectileHitEvent e) { Projectile entity = e.getEntity(); - if(Objects.isNull(entity)) return; - if(Objects.isNull(e.getHitEntity())) return; + if (Objects.isNull(entity)) return; + if (Objects.isNull(e.getHitEntity())) return; List snowballValues = entity.getMetadata("super_snowball"); - if (!snowballValues.isEmpty()) { + if (entity.hasMetadata("super_snowball")) { Entity hitEntity = e.getHitEntity(); - if (!Util.isInvulnerable(hitEntity)){ + if (!Util.isInvulnerable(hitEntity)) { hitEntity.setVelocity(hitEntity.getVelocity().add(hitEntity.getLocation().toVector().subtract(entity.getLocation().add(0, -0.3, 0).toVector()).normalize().multiply(0.5))); hitEntity.setFreezeTicks(Math.max(0, hitEntity.getFreezeTicks()) + 20); if (hitEntity instanceof Player player) player.damage(1); } + } else if (entity.hasMetadata("mana_projectile")) { + ClassAbility.manaBallDamage(e, entity.getMetadata("mana_projectile").get(0).asInt()); } if(entity.hasMetadata("frostfire_fire")){ BlockData newBlockData = FIRE.createBlockData(); @@ -176,7 +198,7 @@ public void grindstoneUse(PrepareResultEvent e){ // Get the enchantmaps of both of the items in the AnvilInventory HashMap firstEnchants = (HashMap) ComplexItemStack.of(inventory.getFirstItem()).getComplexMeta().getComplexEnchants(); HashMap secondEnchants = (HashMap) ComplexItemStack.of(inventory.getSecondItem()).getComplexMeta().getComplexEnchants(); - resultMeta.setComplexEnchantments(EnchantingGUI.combineEnchantMaps(firstEnchants, secondEnchants)); + resultMeta.setComplexEnchantments(EnchantingGui.combineEnchantMaps(firstEnchants, secondEnchants)); resultMeta.updateItem(); e.setResult(resultStack.getItem()); diff --git a/src/main/java/me/zenox/evocraft/events/PlayerUseItemEvent.java b/src/main/java/me/zenox/evocraft/events/PlayerUseItemEvent.java index f3df5e2..e1bcb36 100644 --- a/src/main/java/me/zenox/evocraft/events/PlayerUseItemEvent.java +++ b/src/main/java/me/zenox/evocraft/events/PlayerUseItemEvent.java @@ -2,12 +2,11 @@ import me.zenox.evocraft.EvoCraft; import me.zenox.evocraft.abilities.Ability; -import me.zenox.evocraft.abilities.ItemAbility; +import me.zenox.evocraft.abilities.EventAbility; import me.zenox.evocraft.enchant.ComplexEnchantment; -import me.zenox.evocraft.item.ComplexItemStack; +import me.zenox.evocraft.gameclass.ClassAbilityListener; import org.bukkit.event.*; import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.RegisteredListener; import java.util.ArrayList; @@ -18,7 +17,7 @@ public class PlayerUseItemEvent implements Listener { private final EvoCraft plugin; - private final Map, List> eventToAbilitiesMap = new HashMap<>(); + private final Map, List>> eventToAbilitiesMap = new HashMap<>(); private final Map, List> eventToEnchantmentsMap = new HashMap<>(); @@ -26,7 +25,7 @@ public PlayerUseItemEvent(EvoCraft plugin) { this.plugin = plugin; // Populate eventToAbilitiesMap based on registered abilities - for (Ability ability : Ability.registeredAbilities) { + for (EventAbility ability : Ability.registeredAbilities.stream().filter((x) -> x instanceof EventAbility).map((x) -> (EventAbility) x).toList()) { Class eventType = ability.getEventType(); // Assuming you have a method to get the event type eventToAbilitiesMap .computeIfAbsent(eventType, k -> new ArrayList<>()) @@ -47,10 +46,14 @@ public PlayerUseItemEvent(EvoCraft plugin) { @EventHandler public void useEvent(Event event) { + // check for class abilities + if (event instanceof PlayerInteractEvent && ClassAbilityListener.playerInitiated(((PlayerInteractEvent) event).getPlayer())) + return; + // PERFORMANCE ISSUE: This is called for every event, and every single ability is called. - List relevantAbilities = eventToAbilitiesMap.get(event.getClass()); + List> relevantAbilities = eventToAbilitiesMap.get(event.getClass()); if (relevantAbilities != null) { - for (Ability ability : relevantAbilities) { + for (Ability ability : relevantAbilities) { ability.useAbility(event); } } @@ -62,16 +65,4 @@ public void useEvent(Event event) { } } } - - private void interact(PlayerInteractEvent event) { - ItemStack item = event.getItem(); - if (item == null) return; - ComplexItemStack complexItem = ComplexItemStack.of(item); - for (Ability ability : complexItem.getAbilities()) { - if (ability instanceof ItemAbility) ability.useAbility(event); - } - } - - - } diff --git a/src/main/java/me/zenox/evocraft/gameclass/ClassAbilityListener.java b/src/main/java/me/zenox/evocraft/gameclass/ClassAbilityListener.java new file mode 100644 index 0000000..8ff7987 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/gameclass/ClassAbilityListener.java @@ -0,0 +1,116 @@ +package me.zenox.evocraft.gameclass; + +import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.abilities.ClassAbility; +import me.zenox.evocraft.data.PlayerData; +import me.zenox.evocraft.data.PlayerDataManager; +import me.zenox.evocraft.item.ComplexItem; +import me.zenox.evocraft.util.Util; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.HashMap; + +public class ClassAbilityListener implements Listener { + private final EvoCraft plugin; + // null = SHIFT, l = LEFT_CLICK, r = RIGHT_CLICK + private static final HashMap actionMap = new HashMap<>(); + + public ClassAbilityListener(EvoCraft plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onClassSneak(PlayerToggleSneakEvent event) { + + if (event.isSneaking()){ + // initiator + Player player = event.getPlayer(); + + // filter by player's class + if (GameClass.getClass(player) == null) return; + if (!GameClass.getClass(player).items().contains(ComplexItem.of(player.getEquipment().getItemInMainHand()).getType())) return; + // Prime the ability action bar for PlayerInteractEvent + Util.sendActionBar(event.getPlayer(), "&bSHIFT&7-&b_&7-&b_"); + player.playSound(player.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 2, 0.5f); + actionMap.put(player, null); + + // remove after 1 second unless another action is taken + new BukkitRunnable(){ + @Override + public void run() { + if (actionMap.get(player) == null) + actionMap.remove(player); + } + }.runTaskLater(plugin, 20); + } + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + Action action = event.getAction(); + + // filter by player's class + if (event.getItem() == null) return; + + if (GameClass.getClass(player) == null) return; + if (!GameClass.getClass(player).items().contains(ComplexItem.of(event.getItem()).getType())) return; + + if (actionMap.containsKey(player) && (action.isLeftClick() || action.isRightClick())) { + if (actionMap.get(player) != null){ + // Second Action, has first action + // Effects + player.playSound(player.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 2, 1.5f); + player.playSound(player.getLocation(), Sound.ENTITY_EVOKER_CAST_SPELL, 2, 1); + + Character firstAction = actionMap.get(player); + Util.sendActionBar(event.getPlayer(), "&bSHIFT&7-&b%s&7-&b%s&r".formatted(firstAction, action.toString().charAt(0))); + Util.sendTitle(player, "", "&7Class Ability: &b&l%s&f-&b&l%s&r".formatted(firstAction, action.toString().charAt(0)), 10, 20, 5); + + PlayerData data = PlayerDataManager.getInstance().getPlayerData(player.getUniqueId()); + ClickCombination cc = ClickCombination.getFromChars(firstAction, action.toString().charAt(0)); + + if (cc == null) throw new IllegalStateException("ClickCombination for ability casting is null"); + + GameClass gameClass = data.getPlayerClass(); + ClassAbility ability = gameClass.tree().getAbility(cc); + ability.useAbility(event); + + actionMap.remove(player); // Clear the action after processing the combo + } else { + // First Action + + player.playSound(player.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 2, 1f); + + Util.sendActionBar(event.getPlayer(), "&bSHIFT&7-&b%s&7-&b_".formatted(action.toString().charAt(0))); + actionMap.put(player, action.toString().charAt(0)); + + // remove after 1 second + new BukkitRunnable(){ + @Override + public void run() { + actionMap.remove(player); + } + }.runTaskLater(plugin, 20); + } + } + } + + /** + * Whether a player has initiated the casting of a class ability + * @param player The player to check + * @return Whether the player has initiated the casting of a class ability + */ + public static boolean playerInitiated(Player player){ + return actionMap.containsKey(player); + } + +} diff --git a/src/main/java/me/zenox/evocraft/gameclass/ClickCombination.java b/src/main/java/me/zenox/evocraft/gameclass/ClickCombination.java new file mode 100644 index 0000000..a2e52c8 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/gameclass/ClickCombination.java @@ -0,0 +1,36 @@ +package me.zenox.evocraft.gameclass; + +import org.bukkit.event.block.Action; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public enum ClickCombination { + LEFT_LEFT, + LEFT_RIGHT, + RIGHT_LEFT, + RIGHT_RIGHT; + + public static @Nullable ClickCombination getFromChars(char first, char second) { + return switch (Character.toLowerCase(first)) { + case 'l' -> switch (Character.toLowerCase(second)) { + case 'l' -> LEFT_LEFT; + case 'r' -> LEFT_RIGHT; + default -> null; + }; + case 'r' -> switch (Character.toLowerCase(second)) { + case 'l' -> RIGHT_LEFT; + case 'r' -> RIGHT_RIGHT; + default -> null; + }; + default -> null; + }; + } + + private @Nullable ClickCombination detectCombination(@NotNull Action first, Action second) { + if (first.isLeftClick() && second.isLeftClick()) return ClickCombination.LEFT_LEFT; + if (first.isLeftClick() && second.isRightClick()) return ClickCombination.LEFT_RIGHT; + if (first.isRightClick() && second.isLeftClick()) return ClickCombination.RIGHT_LEFT; + if (first.isRightClick() && second.isRightClick()) return ClickCombination.RIGHT_RIGHT; + return null; // Default case, should ideally not be reached + } +} diff --git a/src/main/java/me/zenox/evocraft/gameclass/GameClass.java b/src/main/java/me/zenox/evocraft/gameclass/GameClass.java new file mode 100644 index 0000000..02347b1 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/gameclass/GameClass.java @@ -0,0 +1,114 @@ +package me.zenox.evocraft.gameclass; + +import me.zenox.evocraft.EvoCraft; +import me.zenox.evocraft.abilities.AbilityRegistry; +import me.zenox.evocraft.data.PlayerDataManager; +import me.zenox.evocraft.data.TranslatableText; +import me.zenox.evocraft.gameclass.tree.AbilityTree; +import me.zenox.evocraft.gui.item.ClassItem; +import me.zenox.evocraft.gui.item.CloseItem; +import me.zenox.evocraft.item.ComplexItem; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import xyz.xenondevs.invui.gui.Gui; + +import java.util.List; + +/** + * Represents a class the player may choose + */ +public enum GameClass { + MAGE("mage", ChatColor.BLUE, + List.of(ComplexItem.Type.STAFF, ComplexItem.Type.WAND), Material.BLAZE_ROD, + new AbilityTree(AbilityRegistry.TELEPORT, AbilityRegistry.MANA_BALL, AbilityRegistry.RIFT_BEAM, AbilityRegistry.RUNE_SHIELD)), + WARRIOR("warrior", ChatColor.RED, + List.of(ComplexItem.Type.SWORD), Material.IRON_SWORD, + new AbilityTree(AbilityRegistry.TRIPLE_SLASH, AbilityRegistry.BLOODLUST, AbilityRegistry.BULL_RUSH, AbilityRegistry.COUNTERSTRIKE)), + TANK("tank", ChatColor.GREEN, + List.of(ComplexItem.Type.AXE), Material.IRON_AXE, + null), + ARCHER("archer", ChatColor.YELLOW, + List.of(ComplexItem.Type.BOW), Material.BOW, + null), + + NONE("none", ChatColor.WHITE, + List.of(), Material.BARRIER, + null); + + private static final NamespacedKey KEY = new NamespacedKey(EvoCraft.getPlugin(), "class"); + private final String id; + private final String name; + private final ChatColor color; + private final String description; + private final List items; + private final Material icon; + private final AbilityTree tree; + + GameClass(String id, ChatColor color, List items, Material icon, AbilityTree tree) { + this.id = id; + this.name = new TranslatableText(TranslatableText.Type.CLASS_NAME + "-" + id).toString(); + this.color = color; + this.description = new TranslatableText(TranslatableText.Type.CLASS_DESC + "-" + id).toString(); + this.items = items; + this.icon = icon; + this.tree = tree; + } + + public static void setClass(Player player, GameClass gameClass) { + PlayerDataManager.getInstance().getPlayerData(player.getUniqueId()).setPlayerClass(gameClass); + } + + public static GameClass getClass(Player player) { + return PlayerDataManager.getInstance().getPlayerData(player.getUniqueId()).getPlayerClass(); + } + + public static GameClass getFromID(String id) { + return switch (id) { + case "mage" -> GameClass.MAGE; + case "warrior" -> GameClass.WARRIOR; + case "tank" -> GameClass.TANK; + case "archer" -> GameClass.ARCHER; + default -> null; + }; + } + + public static Gui getGui() { + return Gui.normal().setStructure( + "# # # # # # # # #", + "# M # W # T # A #", + "# # # # # # # # #" + ) + .addIngredient('M', new ClassItem(GameClass.MAGE)) + .addIngredient('W', new ClassItem(GameClass.WARRIOR)) + .addIngredient('T', new ClassItem(GameClass.TANK)) + .addIngredient('A', new ClassItem(GameClass.ARCHER)) + .addIngredient('C', new CloseItem()) + .build(); + } + + public String id() { + return id; + } + + public ChatColor color() { + return color; + } + + public String description() { + return description; + } + + public List items() { + return items; + } + + public Material icon() { + return icon; + } + + public AbilityTree tree() { + return tree; + } +} diff --git a/src/main/java/me/zenox/evocraft/gameclass/tree/AbilityPath.java b/src/main/java/me/zenox/evocraft/gameclass/tree/AbilityPath.java new file mode 100644 index 0000000..a93151a --- /dev/null +++ b/src/main/java/me/zenox/evocraft/gameclass/tree/AbilityPath.java @@ -0,0 +1,26 @@ +package me.zenox.evocraft.gameclass.tree; + +import me.zenox.evocraft.abilities.ClassAbility; +import me.zenox.evocraft.data.PlayerData; + +/** + * Represents an ability path, which is a linear progression of ability upgrades + */ +public class AbilityPath extends Path { + + public final ClassAbility ability; + + public AbilityPath(String id, ClassAbility ability) { + super(id, ability.getModifiers().size()); + this.ability = ability; + } + + public ClassAbility getAbility() { + return ability; + } + + @Override + public void apply(PlayerData playerData) { + // Nothing, this is just a linear progression with no side effects + } +} diff --git a/src/main/java/me/zenox/evocraft/gameclass/tree/AbilityTree.java b/src/main/java/me/zenox/evocraft/gameclass/tree/AbilityTree.java new file mode 100644 index 0000000..ca73a29 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/gameclass/tree/AbilityTree.java @@ -0,0 +1,48 @@ +package me.zenox.evocraft.gameclass.tree; + +import me.zenox.evocraft.abilities.ClassAbility; +import me.zenox.evocraft.gameclass.ClickCombination; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a global ability tree, including GUI and all + *

+ * Player information can be found in the PlayerData class + */ +public record AbilityTree (ClassAbility LL_Ability, ClassAbility LR_Ability, + ClassAbility RL_Ability, ClassAbility RR_Ability, List paths){ + + public AbilityTree(ClassAbility LL_Ability, ClassAbility LR_Ability, ClassAbility RL_Ability, ClassAbility RR_Ability, Path ... paths) { + this(LL_Ability, LR_Ability, RL_Ability, RR_Ability, new ArrayList<>(List.of( + new AbilityPath(LL_Ability.getId(), LL_Ability), + new AbilityPath(LR_Ability.getId(), LR_Ability), + new AbilityPath(RL_Ability.getId(), RL_Ability), + new AbilityPath(RR_Ability.getId(), RR_Ability)))); + this.paths.addAll(List.of(paths)); + } + + public ClassAbility getAbility(ClickCombination cc){ + return switch(cc){ + case LEFT_LEFT -> LL_Ability; + case LEFT_RIGHT -> LR_Ability; + case RIGHT_LEFT -> RL_Ability; + case RIGHT_RIGHT -> RR_Ability; + }; + } + + public Path path(ClassAbility ability) { + return paths.stream() + .filter(path -> (path instanceof AbilityPath) && ((AbilityPath) path).ability.equals(ability)) + .findFirst() + .orElse(null); + } + + public Path path(String id) { + return paths.stream() + .filter(path -> path.getId().equals(id)) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/java/me/zenox/evocraft/gameclass/tree/Path.java b/src/main/java/me/zenox/evocraft/gameclass/tree/Path.java new file mode 100644 index 0000000..709fb6b --- /dev/null +++ b/src/main/java/me/zenox/evocraft/gameclass/tree/Path.java @@ -0,0 +1,51 @@ +package me.zenox.evocraft.gameclass.tree; + +import me.zenox.evocraft.data.PlayerData; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a player's path on the AbilityTree + */ +public abstract class Path { + + private String id; + + public static final List registeredPaths = new ArrayList<>(); + private final int maxLevel; + + // Constructor + public Path(String id, int maxLevel) { + this.id = id; + this.maxLevel = maxLevel; + registeredPaths.add(this); + } + + public static Path getFromID(String key) { + return registeredPaths.stream() + .filter(path -> path.getId().equals(key)).findFirst() + .orElseThrow(() -> new IllegalArgumentException("No path with ID " + key + " found")); + } + + // Getter for ID + public String getId() { + return id; + } + + // Method to progress the ability + public void progress(PlayerData playerData) { + int currentLevel = playerData.getPathLevel(this); + playerData.setPathLevel(this, currentLevel + 1); + + // Apply the effects to the PlayerData + apply(playerData); + } + + // Abstract method to apply stats, metadata, etc. to player + public abstract void apply(PlayerData playerData); + + public int getMaxLevel() { + return maxLevel; + } +} \ No newline at end of file diff --git a/src/main/java/me/zenox/evocraft/gui/EnchantGUIBuilder.java b/src/main/java/me/zenox/evocraft/gui/EnchantGUIBuilder.java deleted file mode 100644 index 035224b..0000000 --- a/src/main/java/me/zenox/evocraft/gui/EnchantGUIBuilder.java +++ /dev/null @@ -1,46 +0,0 @@ -package me.zenox.evocraft.gui; - -import de.studiocode.invui.gui.GUI; -import de.studiocode.invui.gui.builder.GUIBuilder; -import de.studiocode.invui.gui.builder.GUIContext; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Field; - - -/** - * hhahahh enchant gui code go brr - */ -public class EnchantGUIBuilder extends GUIBuilder { - - private final EnchantGUIType guiType; - private final GUIContext context; - private final Player p; - private final Block block; - - public EnchantGUIBuilder(@NotNull EnchantGUIType guiType, Player p, Block block) { - super(guiType); - this.guiType = guiType; - this.context = new GUIContext(); - try { - Field f = getClass().getSuperclass().getDeclaredField("context"); - f.setAccessible(true); - f.set(this, context); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException(e); - } - - this.p = p; - this.block = block; - } - - @Override - public EnchantingGUI build() { - if (context.getStructure() == null) throw new IllegalStateException("GUIContext has not been set yet."); - return guiType.createGUI(context, p, block); - } - -} - diff --git a/src/main/java/me/zenox/evocraft/gui/EnchantGUIType.java b/src/main/java/me/zenox/evocraft/gui/EnchantGUIType.java deleted file mode 100644 index b0a189e..0000000 --- a/src/main/java/me/zenox/evocraft/gui/EnchantGUIType.java +++ /dev/null @@ -1,37 +0,0 @@ -package me.zenox.evocraft.gui; - -import de.studiocode.invui.gui.builder.GUIContext; -import de.studiocode.invui.gui.builder.guitype.GUIType; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; - -class EnchantGUIType implements GUIType { - - public EnchantingGUI createGUI(GUIContext context, Player p, Block block) { - EnchantingGUI gui = new EnchantingGUI(context.getStructure(), p, block); - gui.setBackground(context.getBackground()); - return gui; - } - - @Override - public EnchantingGUI createGUI(GUIContext context) { - throw new IllegalStateException("You cannot use EnchantGUIType with the normal GUI builder."); - } - - @Override - public boolean acceptsGUIs() { - return false; - } - - @Override - public boolean acceptsItems() { - return false; - } - - @Override - public boolean acceptsInventory() { - return false; - } - -} - diff --git a/src/main/java/me/zenox/evocraft/gui/EnchantGuiBuilder.java b/src/main/java/me/zenox/evocraft/gui/EnchantGuiBuilder.java new file mode 100644 index 0000000..30ef939 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/gui/EnchantGuiBuilder.java @@ -0,0 +1,31 @@ +package me.zenox.evocraft.gui; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import xyz.xenondevs.invui.gui.AbstractGui; + + +/** + * A builder class for {@link EnchantingGui}. + */ +public class EnchantGuiBuilder extends AbstractGui.AbstractBuilder implements EnchantingGui.Enchanting { + + private final Player p; + private final Block block; + + public EnchantGuiBuilder(Player p, Block block) { + this.p = p; + this.block = block; + } + + @Override + public @NotNull EnchantingGui build() { + if (structure == null) + throw new IllegalStateException("Structure is not defined."); + EnchantingGui gui = new EnchantingGui(structure, p, block); + gui.setBackground(background); + return gui; + } +} + diff --git a/src/main/java/me/zenox/evocraft/gui/EnchantingGUI.java b/src/main/java/me/zenox/evocraft/gui/EnchantingGui.java similarity index 76% rename from src/main/java/me/zenox/evocraft/gui/EnchantingGUI.java rename to src/main/java/me/zenox/evocraft/gui/EnchantingGui.java index 574d052..968897a 100644 --- a/src/main/java/me/zenox/evocraft/gui/EnchantingGUI.java +++ b/src/main/java/me/zenox/evocraft/gui/EnchantingGui.java @@ -1,13 +1,7 @@ package me.zenox.evocraft.gui; -import com.archyx.aureliumskills.api.AureliumAPI; -import com.archyx.aureliumskills.skills.Skills; -import de.studiocode.invui.gui.GUI; -import de.studiocode.invui.gui.SlotElement; -import de.studiocode.invui.gui.impl.SimpleGUI; -import de.studiocode.invui.gui.structure.Structure; -import de.studiocode.invui.item.builder.ItemBuilder; -import de.studiocode.invui.virtualinventory.VirtualInventoryManager; +import dev.aurelium.auraskills.api.skill.Skills; +import dev.aurelium.auraskills.api.user.SkillsUser; import me.zenox.evocraft.enchant.ComplexEnchantment; import me.zenox.evocraft.gui.item.BookshelfItem; import me.zenox.evocraft.gui.item.BooleanItem; @@ -18,6 +12,9 @@ import me.zenox.evocraft.item.LoreEntry; import me.zenox.evocraft.item.VariableType; import me.zenox.evocraft.util.Util; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Particle; @@ -26,6 +23,13 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import xyz.xenondevs.inventoryaccess.component.AdventureComponentWrapper; +import xyz.xenondevs.invui.gui.AbstractGui; +import xyz.xenondevs.invui.gui.Gui; +import xyz.xenondevs.invui.gui.SlotElement; +import xyz.xenondevs.invui.gui.structure.Structure; +import xyz.xenondevs.invui.inventory.VirtualInventoryManager; +import xyz.xenondevs.invui.item.builder.ItemBuilder; import java.util.*; @@ -34,7 +38,7 @@ /** * Enchantment GUI that is shown to players */ -public class EnchantingGUI extends SimpleGUI { +public class EnchantingGui extends AbstractGui { public static final VariableType ENCHANT_FUEL_VAR = new VariableType<>("enchant_fuel", new LoreEntry("enchant_fuel", @@ -52,13 +56,13 @@ public class EnchantingGUI extends SimpleGUI { private final Block eTable; private int bookshelfPower = 0; - public EnchantingGUI(int width, int height, Player p, Block eTable) { + public EnchantingGui(int width, int height, Player p, Block eTable) { super(width, height); this.p = p; this.eTable = eTable; } - public EnchantingGUI(@NotNull Structure structure, Player p, Block eTable) { + public EnchantingGui(@NotNull Structure structure, Player p, Block eTable) { super(structure.getWidth(), structure.getHeight()); applyStructure(structure); this.p = p; @@ -82,11 +86,12 @@ public boolean enchantItem(int level, int xpRequired) { ComplexItemStack item = ComplexItemStack.of(getEItem()); ComplexItemStack fuelItem = ComplexItemStack.of(getFuelItem()); Random r = new Random(); + SkillsUser user = Util.getSkillsUser(p); int fuelStrength = (int) (fuelItem.getComplexMeta().getVariable(ENCHANT_FUEL_VAR).getValue()); double variety = calculateVariety(bookshelfPower); - double strength = calculateStrength(level, fuelStrength, AureliumAPI.getSkillLevel(p, Skills.ENCHANTING)); + double strength = calculateStrength(level, fuelStrength, user.getSkillLevel(Skills.ENCHANTING)); // Util.sendMessage(p, "Enchant | Strength: " + strength + " | Variety: " + variety); @@ -151,9 +156,9 @@ public boolean enchantItem(int level, int xpRequired) { fuelItem.getItem().setAmount(fuelItem.getItem().getAmount() - 1); // Set fuel to be empty - VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_FUEL_KEY + p.getName()), 1).setItemStack(null, 0, fuelItem.getItem()); + VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_FUEL_KEY + p.getName()), 1).setItem(null, 0, fuelItem.getItem()); // update virtual container with enchanted version - VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_ITEM_KEY + p.getName()), 1).setItemStack(null, 0, item.getItem()); + VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_ITEM_KEY + p.getName()), 1).setItem(null, 0, item.getItem()); this.eTable.getWorld().playSound(this.eTable.getLocation(), ENCHANT_SOUND, 1f + level, 1f - level * 0.15f); @@ -167,7 +172,7 @@ public boolean enchantItem(int level, int xpRequired) { p.setLevel(p.getLevel() - xpRequired - level + 1); // Update player's Skill XP - AureliumAPI.addXp(p, Skills.ENCHANTING, calculateSkillXP(level, strength, calculateVariety(bookshelfPower))); + user.addSkillXp(Skills.ENCHANTING, calculateSkillXP(level, strength, calculateVariety(bookshelfPower))); return true; } @@ -177,7 +182,7 @@ public boolean enchantItem(int level, int xpRequired) { * @return the item being enchanted */ private ItemStack getEItem() { - return VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_ITEM_KEY + p.getName()), 1).getItemStack(0); + return VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_ITEM_KEY + p.getName()), 1).getItem(0); } /** @@ -186,7 +191,7 @@ private ItemStack getEItem() { * @return the fuel item */ private ItemStack getFuelItem() { - return VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_FUEL_KEY + p.getName()), 1).getItemStack(0); + return VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_FUEL_KEY + p.getName()), 1).getItem(0); } public Block getETable() { @@ -197,23 +202,24 @@ public void setBookshelfPower(int bookshelfPower) { this.bookshelfPower = bookshelfPower; } - public static boolean enchantValid(EnchantingGUI gui, int power, int XPRequired) { + public static boolean enchantValid(EnchantingGui gui, int power, int XPRequired) { + SkillsUser user = Util.getSkillsUser(gui.p); int skillRequirement = 0; switch (power) { case 2 -> skillRequirement = 10; case 3 -> skillRequirement = 25; } // Check XP and skill level - return fuelValid(gui.getFuelItem()) && itemValid(gui.getEItem()) && AureliumAPI.getSkillLevel(gui.p, Skills.ENCHANTING) >= skillRequirement && gui.p.getLevel() >= XPRequired; + return fuelValid(gui.getFuelItem()) && itemValid(gui.getEItem()) && user.getSkillLevel(Skills.ENCHANTING) >= skillRequirement && gui.p.getLevel() >= XPRequired; } private static boolean itemValid(ItemStack item) { try { - ComplexItem.Type type = ComplexItemStack.of(item).getComplexItem().getType(); - return item.getType() != Material.AIR && ComplexEnchantment.getRegisteredEnchants() + ComplexItem.Type type = ComplexItem.of(item).getType(); + return item.getType() != Material.AIR && !ComplexEnchantment.getRegisteredEnchants() .stream() .filter(complexEnchantment -> - complexEnchantment.getTypes().contains(type)).toList().size() > 0; + complexEnchantment.getTypes().contains(type)).toList().isEmpty(); } catch (NullPointerException e) { return false; } @@ -275,8 +281,8 @@ private static int combineEnchantLevels(int maxLevel, int enchantLevel1, int enc return Math.min(maxLevel, result); } - public static GUI getGui(Player p, Block block) { - return new EnchantGUIBuilder(GUITypes.ENCHANT, p, block) + public static Gui getGui(Player p, Block block) { + return new EnchantGuiBuilder(p, block) .setStructure( "# # # # # $ $ 1 #", "# # # # # $ # # #", @@ -285,8 +291,28 @@ public static GUI getGui(Player p, Block block) { "# # # # # ^ ^ 3 #", "# # # # C B # # #" ) - .addIngredient('E', new SlotElement.VISlotElement(VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_ITEM_KEY + p.getName()), 1), 0, new ItemBuilder(Material.GRAY_STAINED_GLASS_PANE))) - .addIngredient('F', new SlotElement.VISlotElement(VirtualInventoryManager.getInstance().getOrCreate(Util.constantUUID(ENCHANT_GUI_FUEL_KEY + p.getName()), 1), 0, new ItemBuilder(Material.BLUE_STAINED_GLASS_PANE))) + .addIngredient('E', new SlotElement.InventorySlotElement(VirtualInventoryManager.getInstance() + .getOrCreate(Util.constantUUID(ENCHANT_GUI_ITEM_KEY + p.getName()), 1), 0, + new ItemBuilder(Material.GRAY_STAINED_GLASS_PANE) + .setDisplayName(new AdventureComponentWrapper( + Component.text("Enchanting Slot").color(NamedTextColor.LIGHT_PURPLE))) + .setLore(List.of( + new AdventureComponentWrapper( + Component.text("The enchanting table funnels its energy through this slot, adding mystical properties to the item.") + .color(NamedTextColor.GRAY).decorate(TextDecoration.ITALIC) + ), + new AdventureComponentWrapper(Component.text("")), + new AdventureComponentWrapper( + Component.text("→ Place an item here to enchant it.").color(NamedTextColor.YELLOW) + ) + )))) + .addIngredient('F', new SlotElement.InventorySlotElement(VirtualInventoryManager.getInstance() + .getOrCreate(Util.constantUUID(ENCHANT_GUI_FUEL_KEY + p.getName()), 1), 0, + new ItemBuilder(Material.BLUE_STAINED_GLASS_PANE) + .setDisplayName(new AdventureComponentWrapper( + Component.text("Enchant Fuel").color(NamedTextColor.BLUE))) + .setLore(List.of(new AdventureComponentWrapper( + Component.text("→ Place an item here to use it as enchant fuel").color(NamedTextColor.YELLOW)))))) .addIngredient('R', new ItemBuilder(Material.RED_STAINED_GLASS_PANE).setDisplayName("")) .addIngredient('1', new EnchantItem(1, 0)) .addIngredient('2', new EnchantItem(2, 10)) @@ -299,4 +325,6 @@ public static GUI getGui(Player p, Block block) { .addIngredient('C', new CloseItem()) .build(); } + + interface Enchanting extends Gui.Builder {} } diff --git a/src/main/java/me/zenox/evocraft/gui/GUITypes.java b/src/main/java/me/zenox/evocraft/gui/GUITypes.java deleted file mode 100644 index 2be3ebf..0000000 --- a/src/main/java/me/zenox/evocraft/gui/GUITypes.java +++ /dev/null @@ -1,6 +0,0 @@ -package me.zenox.evocraft.gui; - -public class GUITypes { - - public static EnchantGUIType ENCHANT = new EnchantGUIType(); -} diff --git a/src/main/java/me/zenox/evocraft/gui/item/BookshelfItem.java b/src/main/java/me/zenox/evocraft/gui/item/BookshelfItem.java index 5bf74f4..eebbc98 100644 --- a/src/main/java/me/zenox/evocraft/gui/item/BookshelfItem.java +++ b/src/main/java/me/zenox/evocraft/gui/item/BookshelfItem.java @@ -1,9 +1,9 @@ package me.zenox.evocraft.gui.item; -import de.studiocode.invui.item.ItemProvider; -import de.studiocode.invui.item.builder.ItemBuilder; -import de.studiocode.invui.item.impl.controlitem.ControlItem; -import me.zenox.evocraft.gui.EnchantingGUI; +import xyz.xenondevs.invui.item.ItemProvider; +import xyz.xenondevs.invui.item.builder.ItemBuilder; +import xyz.xenondevs.invui.item.impl.controlitem.ControlItem; +import me.zenox.evocraft.gui.EnchantingGui; import me.zenox.evocraft.util.Util; import org.bukkit.Material; import org.bukkit.block.Block; @@ -17,12 +17,12 @@ /** * Bookshelf Counter Item for EnchantingTable */ -public class BookshelfItem extends ControlItem { +public class BookshelfItem extends ControlItem { - private EnchantingGUI gui; + private EnchantingGui gui; @Override - public ItemProvider getItemProvider(EnchantingGUI gui) { + public ItemProvider getItemProvider(EnchantingGui gui) { this.gui = gui; int bookshelfPower = 0; for (Block block : Util.getNearbyBlocks(gui.getETable().getLocation(), 5, 5)) diff --git a/src/main/java/me/zenox/evocraft/gui/item/BooleanItem.java b/src/main/java/me/zenox/evocraft/gui/item/BooleanItem.java index e9a4479..e30370c 100644 --- a/src/main/java/me/zenox/evocraft/gui/item/BooleanItem.java +++ b/src/main/java/me/zenox/evocraft/gui/item/BooleanItem.java @@ -1,9 +1,9 @@ package me.zenox.evocraft.gui.item; -import de.studiocode.invui.item.ItemProvider; -import de.studiocode.invui.item.builder.ItemBuilder; -import de.studiocode.invui.item.impl.controlitem.ControlItem; -import me.zenox.evocraft.gui.EnchantingGUI; +import xyz.xenondevs.invui.item.ItemProvider; +import xyz.xenondevs.invui.item.builder.ItemBuilder; +import xyz.xenondevs.invui.item.impl.controlitem.ControlItem; +import me.zenox.evocraft.gui.EnchantingGui; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; @@ -15,34 +15,34 @@ /** * Item that represents a boolean and changes based on boolean */ -public class BooleanItem extends ControlItem { +public class BooleanItem extends ControlItem { - private Predicate supplier; + private final Predicate supplier; private ItemProvider trueItem = new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE).setDisplayName("§r"); private ItemProvider falseItem = new ItemBuilder(Material.RED_STAINED_GLASS_PANE).setDisplayName("§r"); - public BooleanItem(Predicate supplier, ItemProvider trueItem, ItemProvider falseItem){ + public BooleanItem(Predicate supplier, ItemProvider trueItem, ItemProvider falseItem){ super(); this.supplier = supplier; this.trueItem = trueItem; this.falseItem = falseItem; } - public BooleanItem(Predicate supplier, ItemProvider trueItem){ + public BooleanItem(Predicate supplier, ItemProvider trueItem){ super(); this.supplier = supplier; this.trueItem = trueItem; } - public BooleanItem(Predicate supplier){ + public BooleanItem(Predicate supplier){ super(); this.supplier = supplier; } - private EnchantingGUI gui; + private EnchantingGui gui; @Override - public ItemProvider getItemProvider(EnchantingGUI gui) { + public ItemProvider getItemProvider(EnchantingGui gui) { this.gui = gui; return supplier.test(gui) ? trueItem : falseItem; } diff --git a/src/main/java/me/zenox/evocraft/gui/item/ClassItem.java b/src/main/java/me/zenox/evocraft/gui/item/ClassItem.java new file mode 100644 index 0000000..fc014d1 --- /dev/null +++ b/src/main/java/me/zenox/evocraft/gui/item/ClassItem.java @@ -0,0 +1,46 @@ +package me.zenox.evocraft.gui.item; + +import xyz.xenondevs.invui.item.ItemProvider; +import xyz.xenondevs.invui.item.builder.ItemBuilder; +import xyz.xenondevs.invui.item.impl.AbstractItem; +import xyz.xenondevs.invui.window.Window; +import me.zenox.evocraft.data.TranslatableList; +import me.zenox.evocraft.data.TranslatableText; +import me.zenox.evocraft.gameclass.GameClass; +import me.zenox.evocraft.util.Util; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemFlag; +import org.jetbrains.annotations.NotNull; + +public class ClassItem extends AbstractItem { + private final GameClass gameClass; + private final TranslatableText NAME; + private final TranslatableList LORE; + + public ClassItem(GameClass gameClass){ + super(); + this.gameClass = gameClass; + this.NAME = new TranslatableText(TranslatableText.Type.GUI + "-class-action-title-" + gameClass.name().toLowerCase()); + this.LORE = new TranslatableList(TranslatableText.Type.GUI + "-class-action-lore-" + gameClass.name().toLowerCase()); + } + + @Override + public ItemProvider getItemProvider() { + return new ItemBuilder(gameClass.icon()).setDisplayName(NAME.toString()).setLegacyLore(LORE.getList()).addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + } + + @Override + public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) { + // set the class of a player + Util.sendMessage(player, "You have selected the " + gameClass.name() + " class!"); + GameClass.setClass(player, gameClass); + for (Window window : getWindows()) { + if(window.getCurrentViewer().equals(player)){ + window.close(); + } + } + } +} + diff --git a/src/main/java/me/zenox/evocraft/gui/item/CloseItem.java b/src/main/java/me/zenox/evocraft/gui/item/CloseItem.java index 2652a72..b76a1fb 100644 --- a/src/main/java/me/zenox/evocraft/gui/item/CloseItem.java +++ b/src/main/java/me/zenox/evocraft/gui/item/CloseItem.java @@ -1,25 +1,25 @@ package me.zenox.evocraft.gui.item; -import de.studiocode.invui.gui.impl.SimpleGUI; -import de.studiocode.invui.item.ItemProvider; -import de.studiocode.invui.item.builder.ItemBuilder; -import de.studiocode.invui.item.impl.controlitem.ControlItem; -import de.studiocode.invui.window.Window; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; import org.jetbrains.annotations.NotNull; +import xyz.xenondevs.invui.gui.AbstractGui; +import xyz.xenondevs.invui.item.ItemProvider; +import xyz.xenondevs.invui.item.builder.ItemBuilder; +import xyz.xenondevs.invui.item.impl.controlitem.ControlItem; +import xyz.xenondevs.invui.window.Window; /** * "Empty" item that can be replaced with another item via clicking on it */ -public class CloseItem extends ControlItem { +public class CloseItem extends ControlItem { - private SimpleGUI gui; + private AbstractGui gui; @Override - public ItemProvider getItemProvider(SimpleGUI gui) { + public ItemProvider getItemProvider(AbstractGui gui) { this.gui = gui; return new ItemBuilder(Material.BARRIER).setDisplayName("§cClose Menu"); } @@ -29,7 +29,7 @@ public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @N for (Window window : getWindows()) { if(window.getCurrentViewer().equals(player)){ - window.closeForViewer(); + window.close(); } } } diff --git a/src/main/java/me/zenox/evocraft/gui/item/EmptyItem.java b/src/main/java/me/zenox/evocraft/gui/item/EmptyItem.java index 67fa81a..a782197 100644 --- a/src/main/java/me/zenox/evocraft/gui/item/EmptyItem.java +++ b/src/main/java/me/zenox/evocraft/gui/item/EmptyItem.java @@ -1,8 +1,8 @@ package me.zenox.evocraft.gui.item; -import de.studiocode.invui.item.ItemProvider; -import de.studiocode.invui.item.builder.ItemBuilder; -import de.studiocode.invui.item.impl.BaseItem; +import xyz.xenondevs.invui.item.ItemProvider; +import xyz.xenondevs.invui.item.builder.ItemBuilder; +import xyz.xenondevs.invui.item.impl.AbstractItem; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; @@ -13,7 +13,7 @@ /** * "Empty" item that can be replaced with another item via clicking on it */ -public class EmptyItem extends BaseItem { +public class EmptyItem extends AbstractItem { private ItemStack item = new ItemStack(Material.AIR); diff --git a/src/main/java/me/zenox/evocraft/gui/item/EnchantItem.java b/src/main/java/me/zenox/evocraft/gui/item/EnchantItem.java index f4518d9..94a7716 100644 --- a/src/main/java/me/zenox/evocraft/gui/item/EnchantItem.java +++ b/src/main/java/me/zenox/evocraft/gui/item/EnchantItem.java @@ -1,18 +1,18 @@ package me.zenox.evocraft.gui.item; -import de.studiocode.invui.item.ItemProvider; -import de.studiocode.invui.item.builder.ItemBuilder; -import de.studiocode.invui.item.impl.controlitem.ControlItem; +import xyz.xenondevs.invui.item.ItemProvider; +import xyz.xenondevs.invui.item.builder.ItemBuilder; +import xyz.xenondevs.invui.item.impl.controlitem.ControlItem; import me.zenox.evocraft.data.TranslatableList; import me.zenox.evocraft.data.TranslatableText; -import me.zenox.evocraft.gui.EnchantingGUI; +import me.zenox.evocraft.gui.EnchantingGui; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; import org.jetbrains.annotations.NotNull; -public class EnchantItem extends ControlItem { +public class EnchantItem extends ControlItem { private final int level; private final int skillreq; @@ -27,17 +27,17 @@ public EnchantItem(int level, int skillreq){ this.LORE = new TranslatableList(TranslatableText.Type.GUI + "-enchant-action-lore-" + level); } - private EnchantingGUI gui; + private EnchantingGui gui; @Override - public ItemProvider getItemProvider(EnchantingGUI gui) { + public ItemProvider getItemProvider(EnchantingGui gui) { this.gui = gui; return new ItemBuilder(Material.EXPERIENCE_BOTTLE).setDisplayName(NAME.toString()).setLegacyLore(LORE.getList()).setAmount(level); } @Override public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) { - if(EnchantingGUI.enchantValid(gui, level, getXPRequired())) gui.enchantItem(level, getXPRequired()); + if(EnchantingGui.enchantValid(gui, level, getXPRequired())) gui.enchantItem(level, getXPRequired()); } public int getXPRequired(){ diff --git a/src/main/java/me/zenox/evocraft/item/ComplexItem.java b/src/main/java/me/zenox/evocraft/item/ComplexItem.java index 8fc6a4e..181308d 100644 --- a/src/main/java/me/zenox/evocraft/item/ComplexItem.java +++ b/src/main/java/me/zenox/evocraft/item/ComplexItem.java @@ -1,10 +1,10 @@ package me.zenox.evocraft.item; -import com.archyx.aureliumskills.stats.Stat; import com.google.common.primitives.Ints; +import dev.aurelium.auraskills.api.stat.Stats; import me.zenox.evocraft.EvoCraft; import me.zenox.evocraft.abilities.Ability; -import me.zenox.evocraft.abilities.ItemAbility; +import me.zenox.evocraft.abilities.itemabilities.ItemAbility; import me.zenox.evocraft.attribute.AttributeModifier; import me.zenox.evocraft.data.TranslatableList; import me.zenox.evocraft.data.TranslatableText; @@ -15,6 +15,8 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; import java.io.Serializable; import java.util.ArrayList; @@ -25,7 +27,7 @@ @SuppressWarnings("UnstableApiUsage") public class ComplexItem { - public static final List itemRegistry = new ArrayList<>(); + public static final HashMap itemRegistry = new HashMap<>(); public static final NamespacedKey GLOBAL_ID = new NamespacedKey(EvoCraft.getPlugin(), "evocraft"); public static final NamespacedKey GLOW_ID = new NamespacedKey(EvoCraft.getPlugin(), "glow"); @@ -41,15 +43,15 @@ public class ComplexItem { private final Type type; private final Material material; private final ItemMeta meta; - private final Map stats; - private final List abilities; + private final Map stats; + private final List> abilities; private final HashMap variableMap = new HashMap<>(); private final List attributeModifiers; private String skullURL; - public ComplexItem(String id, Boolean unique, Boolean glow, Rarity rarity, Type type, Material material, Map stats, List abilities, HashMap variableMap, List attributeModifiers) { + public ComplexItem(String id, Boolean unique, Boolean glow, Rarity rarity, Type type, Material material, Map stats, List> abilities, HashMap variableMap, List attributeModifiers) { this.id = id; this.name = new TranslatableText(TranslatableText.Type.ITEM_NAME + "-" + id); this.lore = new TranslatableList(TranslatableText.Type.ITEM_LORE + "-" + id); @@ -71,15 +73,15 @@ public ComplexItem(String id, Boolean unique, Boolean glow, Rarity rarity, Type register(false); } - public ComplexItem(String id, Boolean unique, Rarity rarity, Type type, Material material, Map stats, List abilities) { + public ComplexItem(String id, Boolean unique, Rarity rarity, Type type, Material material, Map stats, List> abilities) { this(id, unique, false, rarity, type, material, stats, abilities, new HashMap<>(), new ArrayList<>()); } - public ComplexItem(String id, Rarity rarity, Type type, Material material, Map stats, List abilities) { + public ComplexItem(String id, Rarity rarity, Type type, Material material, Map stats, List> abilities) { this(id, false, rarity, type, material, stats, abilities); } - public ComplexItem(String id, Rarity rarity, Type type, Material material, Map stats) { + public ComplexItem(String id, Rarity rarity, Type type, Material material, Map stats) { this(id, false, rarity, type, material, stats, List.of()); } @@ -87,7 +89,7 @@ public ComplexItem(String id, Rarity rarity, Type type, Material material) { this(id, false, rarity, type, material, Map.of(), List.of()); } - public ComplexItem(ItemSettings settings) { + public ComplexItem(ItemSettings settings, boolean override) { this.name = new TranslatableText(TranslatableText.Type.ITEM_NAME + "-" + settings.getId()); this.id = settings.getId(); this.lore = new TranslatableList(TranslatableText.Type.ITEM_LORE + "-" + id); @@ -106,46 +108,35 @@ public ComplexItem(ItemSettings settings) { this.variableMap.putAll(settings.getVariableMap()); this.attributeModifiers = settings.getAttributeModifiers(); - register(false); + register(override); } - protected ComplexItem(ItemSettings settings, boolean override) { - this.name = new TranslatableText(TranslatableText.Type.ITEM_NAME + "-" + settings.getId()); - this.id = settings.getId(); - this.lore = new TranslatableList(TranslatableText.Type.ITEM_LORE + "-" + id); - this.key = new NamespacedKey(EvoCraft.getPlugin(), id); - String str = String.valueOf(Math.abs(id.hashCode())); - this.customModelData = Ints.tryParse(str.substring(0, Math.min(7, str.length()))); - this.unique = settings.isUnique(); - this.glow = settings.doesGlow(); - this.rarity = settings.getRarity(); - this.type = settings.getType(); - this.material = settings.getMaterial(); - this.meta = settings.getMeta(); - this.stats = settings.getStats(); - this.skullURL = ""; - this.abilities = settings.getAbilities() == null ? new ArrayList<>() : new ArrayList<>(settings.getAbilities()); - this.variableMap.putAll(settings.getVariableMap()); - this.attributeModifiers = settings.getAttributeModifiers(); + public ComplexItem(ItemSettings settings) { + this(settings, false); + } - register(true); + /** + * Faster, more streamlined method to fetch the ComplexItem attribute without having to read or update ComplexItemMeta + * + * @param item The item to get the ComplexItem from + * @return The ComplexItem object of the item + */ + public static ComplexItem of(ItemStack item) { + if (item == null) return null; + if (item.getItemMeta() == null) return VanillaItem.of(item.getType()); + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + if (container.has(GLOBAL_ID, PersistentDataType.STRING)) + return itemRegistry.get(container.get(GLOBAL_ID, PersistentDataType.STRING)); + else return VanillaItem.of(item.getType()); } private void register(boolean override){ - for (ComplexItem item: - new ArrayList<>(itemRegistry)) { - if (item.getId().equalsIgnoreCase(id)) { - if (!override) { - Util.logToConsole("Duplicate ComplexItem ID: " + id + " | Exact Match: " + item.equals(this)); - throw new IllegalArgumentException("ComplexItem ID cannot be duplicate"); - } else { - itemRegistry.remove(item); - break; - } - } + if (itemRegistry.containsKey(id) && !override) { + Util.logToConsole("Duplicate ComplexItem ID: " + id + " | Exact Match: " + itemRegistry.get(id).equals(this)); + throw new IllegalArgumentException("ComplexItem ID cannot be duplicate"); } - itemRegistry.add(this); + itemRegistry.put(id, this); } @@ -159,7 +150,7 @@ public ItemStack getItemStack(Integer amount) { } protected void writeAbilityLore(List lore) { - for (Ability ability : this.abilities) { + for (Ability ability : this.abilities) { lore.add(""); lore.add(ChatColor.GOLD + "Ability: " + ability.getDisplayName() + ChatColor.YELLOW + ChatColor.BOLD + " " + (ability instanceof ItemAbility ? ((ItemAbility) ability).getAction().getName() : "")); lore.addAll(ability.getLore()); @@ -216,7 +207,7 @@ public Type getType() { return this.type; } - public Map getStats() { + public Map getStats() { return stats; } @@ -232,7 +223,7 @@ public void setSkullURL(String URL) { this.skullURL = URL; } - public List getAbilities() { + public List> getAbilities() { return this.abilities; } diff --git a/src/main/java/me/zenox/evocraft/item/ComplexItemMeta.java b/src/main/java/me/zenox/evocraft/item/ComplexItemMeta.java index 4a28d1f..f6f86bd 100644 --- a/src/main/java/me/zenox/evocraft/item/ComplexItemMeta.java +++ b/src/main/java/me/zenox/evocraft/item/ComplexItemMeta.java @@ -1,19 +1,20 @@ package me.zenox.evocraft.item; -import com.archyx.aureliumskills.modifier.ModifierType; -import com.archyx.aureliumskills.modifier.StatModifier; -import com.archyx.aureliumskills.stats.Stats; +import dev.aurelium.auraskills.api.AuraSkillsBukkit; +import dev.aurelium.auraskills.api.item.ItemManager; +import dev.aurelium.auraskills.api.item.ModifierType; +import dev.aurelium.auraskills.api.stat.StatModifier; +import dev.aurelium.auraskills.api.stat.Stats; import me.zenox.evocraft.EvoCraft; import me.zenox.evocraft.abilities.Ability; -import me.zenox.evocraft.abilities.FullSetArmorAbility; -import me.zenox.evocraft.abilities.ItemAbility; +import me.zenox.evocraft.abilities.itemabilities.FullSetArmorAbility; +import me.zenox.evocraft.abilities.itemabilities.ItemAbility; import me.zenox.evocraft.attribute.AttributeModifier; import me.zenox.evocraft.attribute.types.AureliumAttribute; import me.zenox.evocraft.enchant.ComplexEnchantment; import me.zenox.evocraft.persistence.ArrayListType; import me.zenox.evocraft.persistence.SerializedPersistentType; import me.zenox.evocraft.util.Romans; -import me.zenox.evocraft.util.Util; import org.bukkit.ChatColor; import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; @@ -41,7 +42,6 @@ */ public class ComplexItemMeta { - public static final NamespacedKey ABILITY_ID = new NamespacedKey(EvoCraft.getPlugin(), "ability"); public static final String VAR_PREFIX = "var_"; public static final String ATTRIBUTE_BASE_KEY = "base"; public static final VariableType RARITY_VAR = new VariableType<>("rarity", new LoreEntry("rarity", List.of("Rarity Lore")), VariableType.Priority.BELOW, (loreEntry, variable) -> loreEntry.setLore(List.of(((ComplexItem.Rarity) variable.getValue()).color() + ((ComplexItem.Rarity) variable.getValue()).getName()))); @@ -52,22 +52,19 @@ public class ComplexItemMeta { })), VariableType.Priority.BELOW, (loreEntry, variable) -> loreEntry.setLore(List.of(((ComplexItem.Type) variable.getValue()).getName()))); public static final NamespacedKey ENCHANT_KEY = new NamespacedKey(EvoCraft.getPlugin(), "complexEnchants"); private static final NamespacedKey ATTRIBUTE_KEY = new NamespacedKey(EvoCraft.getPlugin(), "attributes"); - private List abilities; + + private static final ItemManager itemManager = AuraSkillsBukkit.get().getItemManager(); + private final List variableList = new ArrayList<>(); private HashMap complexEnchantments = new HashMap<>(); private List modifierList = new ArrayList<>(); private final ComplexItemStack complexItemStack; - public ComplexItemMeta(ComplexItemStack complexItemStack, List abilities) { - this.abilities = abilities == null ? new ArrayList<>() : new ArrayList<>(abilities); + public ComplexItemMeta(ComplexItemStack complexItemStack) { this.complexItemStack = complexItemStack; this.read(); } - public ComplexItemMeta(ComplexItemStack complexItemStack) { - this(complexItemStack, complexItemStack.getComplexItem().getAbilities()); - } - /** * Updates the ItemStack to match the current ComplexItemMeta */ @@ -95,7 +92,7 @@ public void updateItem() { Arrays.stream(Attribute.values()).forEach(meta::removeAttributeModifier); item.setItemMeta(meta); - Arrays.stream(Stats.values()).forEach(stats -> item.setItemMeta(Util.removeAureliumModifier(item, ((ComplexItem.Type) getVariable(TYPE_VAR).getValue()).isWearable() ? ModifierType.ARMOR : ModifierType.ITEM, stats).getItemMeta())); + Arrays.stream(Stats.values()).forEach(stats -> item.setItemMeta(itemManager.removeStatModifier(item, ((ComplexItem.Type) getVariable(TYPE_VAR).getValue()).isWearable() ? ModifierType.ARMOR : ModifierType.ITEM, stats).getItemMeta())); meta = item.getItemMeta(); @@ -133,7 +130,7 @@ public void updateItem() { } // Write ComplexEnchants - dataContainer.set(ENCHANT_KEY, new SerializedPersistentType(), complexEnchMap); + dataContainer.set(ENCHANT_KEY, new SerializedPersistentType<>(), complexEnchMap); // Clear vanilla enchantments for (Enchantment enchant: @@ -159,7 +156,6 @@ public void updateItem() { // Write Abilities writeAbilityLore(lore); - dataContainer.set(ABILITY_ID, new ArrayListType(), new ArrayList<>(abilities.stream().map(Ability::getId).toList())); writeVariables(VariableType.Priority.BELOW_ABILITIES, dataContainer, lore, true); @@ -257,7 +253,7 @@ private void writeVariables(VariableType.Priority priority, PersistentDataContai } private void writeAbilityLore(LoreBuilder loreBuilder) { - for (Ability ability : this.abilities) { + for (Ability ability : complexItemStack.getComplexItem().getAbilities()) { List lore = new ArrayList<>(); lore.add(ChatColor.GOLD + (ability.isPassive() ? "Passive " : "") + (ability instanceof FullSetArmorAbility ? "Full Set " : "") + "Ability: " + ability.getDisplayName() + ChatColor.YELLOW + ChatColor.BOLD + " " + (ability instanceof ItemAbility ? ((ItemAbility) ability).getAction().getName() : "")); lore.addAll(ability.getLore()); @@ -287,7 +283,7 @@ private void writeAbilityLore(LoreBuilder loreBuilder) { // Read AureliumSkills Modifiers for(StatModifier modifier : - Util.getAureliumModifiers(stack.getItem(), + itemManager.getStatModifiers(stack.getItem(), ((ComplexItem.Type) meta.getVariable(ComplexItemMeta.TYPE_VAR).getValue()).isWearable() ? ModifierType.ARMOR : ModifierType.ITEM)){ modifiers.add(AttributeModifier.of(modifier)); } @@ -358,10 +354,6 @@ public List getVariableList() { return variableList; } - public List getAbilities() { - return abilities; - } - public List getModifierList() { return modifierList; } diff --git a/src/main/java/me/zenox/evocraft/item/ComplexItemStack.java b/src/main/java/me/zenox/evocraft/item/ComplexItemStack.java index e35bf59..7ab7243 100644 --- a/src/main/java/me/zenox/evocraft/item/ComplexItemStack.java +++ b/src/main/java/me/zenox/evocraft/item/ComplexItemStack.java @@ -1,7 +1,9 @@ package me.zenox.evocraft.item; -import com.archyx.aureliumskills.api.AureliumAPI; -import com.archyx.aureliumskills.stats.Stat; +import dev.aurelium.auraskills.api.AuraSkillsBukkit; +import dev.aurelium.auraskills.api.item.ItemManager; +import dev.aurelium.auraskills.api.item.ModifierType; +import dev.aurelium.auraskills.api.stat.Stats; import me.zenox.evocraft.EvoCraft; import me.zenox.evocraft.abilities.Ability; import me.zenox.evocraft.enchant.ComplexEnchantment; @@ -17,7 +19,10 @@ import org.jetbrains.annotations.NotNull; import java.io.Serializable; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; /** * Class that represents a "custom" ItemStack. @@ -35,7 +40,9 @@ public class ComplexItemStack { private ItemStack item; private ComplexItemMeta complexMeta; - private String skullURL; + private final String skullURL; + + private final static ItemManager itemManager = AuraSkillsBukkit.get().getItemManager(); public ComplexItemStack(ComplexItem complexItem, int amount) { this(complexItem, new ItemStack(complexItem.getMaterial())); @@ -76,7 +83,7 @@ public static ComplexItemStack of(@NotNull ItemStack item) { Map vanillaEnchantments = item.getEnchantments(); - ComplexItem complexItem = Objects.requireNonNullElse(ItemRegistry.byItem(item), VanillaItem.of(item.getType())); + ComplexItem complexItem = Objects.requireNonNullElse(ComplexItem.of(item), VanillaItem.of(item.getType())); ComplexItemStack cItem = new ComplexItemStack(complexItem, item); // add vanilla variables??? @@ -126,8 +133,9 @@ private ItemStack buildItem(int amount) { item.setItemMeta(meta); // Set stats and clone - for (Map.Entry entry : complexItem.getStats().entrySet()) { - item = complexItem.getType().isWearable() ? AureliumAPI.addArmorModifier(item, entry.getKey(), entry.getValue(), false) : AureliumAPI.addItemModifier(item, entry.getKey(), entry.getValue(), false); + for (Map.Entry entry : complexItem.getStats().entrySet()) { + ModifierType type = complexItem.getType().isWearable() ? ModifierType.ARMOR : ModifierType.ITEM; + item = itemManager.addStatModifier(item, type, entry.getKey(), entry.getValue(), false); } meta = item.getItemMeta(); @@ -173,8 +181,8 @@ public NamespacedKey getKey() { return this.complexItem.getKey(); } - public List getAbilities() { - return this.complexMeta.getAbilities(); + public List> getAbilities() { + return this.complexItem.getAbilities(); } public ComplexItem getComplexItem() { diff --git a/src/main/java/me/zenox/evocraft/item/ItemRegistry.java b/src/main/java/me/zenox/evocraft/item/ItemRegistry.java index d50f50b..e4a767b 100644 --- a/src/main/java/me/zenox/evocraft/item/ItemRegistry.java +++ b/src/main/java/me/zenox/evocraft/item/ItemRegistry.java @@ -1,11 +1,15 @@ package me.zenox.evocraft.item; -import com.archyx.aureliumskills.stats.Stats; -import me.zenox.evocraft.abilities.*; +import dev.aurelium.auraskills.api.stat.Stats; +import me.zenox.evocraft.abilities.AbilityRegistry; +import me.zenox.evocraft.abilities.ElementalFlux; +import me.zenox.evocraft.abilities.itemabilities.specific.Crucify; +import me.zenox.evocraft.abilities.itemabilities.specific.EmberAttune; +import me.zenox.evocraft.abilities.itemabilities.specific.Psychic; +import me.zenox.evocraft.abilities.itemabilities.specific.Transcendence; import me.zenox.evocraft.attribute.AttributeRegistry; -import me.zenox.evocraft.gui.EnchantingGUI; +import me.zenox.evocraft.gui.EnchantingGui; import me.zenox.evocraft.item.basicitems.CorruptPearl; -import me.zenox.evocraft.item.basicitems.GardenerSapling; import me.zenox.evocraft.item.basicitems.RavagerSkin; import me.zenox.evocraft.item.basicitems.TormentedSoul; import me.zenox.evocraft.util.Util; @@ -15,20 +19,13 @@ import org.bukkit.Material; import org.bukkit.attribute.AttributeModifier; import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import java.util.Objects; public class ItemRegistry { - - public static final ComplexItem GARDENER_SAPLING = new GardenerSapling(); public static final ComplexItem ENCHANTED_MAGMA_BLOCK = new ComplexItem(new ItemSettings() .id("enchanted_magma_block") .material(Material.MAGMA_BLOCK)); @@ -224,7 +221,7 @@ public class ItemRegistry { .modifier(AttributeRegistry.ATTACK_DAMAGE, 15) .modifier(AttributeRegistry.ATTACK_SPEED, -3) .modifier(AttributeRegistry.WISDOM, 50) - .abilities(AbilityRegistry.VOID_WARP, AbilityRegistry.VOIDULAR_RECALL) + .abilities(AbilityRegistry.VOID_WARP) .rarity(ComplexItem.Rarity.EPIC) .material(Material.NETHERITE_SHOVEL) .type(ComplexItem.Type.STAFF) @@ -342,7 +339,7 @@ public class ItemRegistry { .rarity(ComplexItem.Rarity.COMMON) .type(ComplexItem.Type.ENCHANTING_FUEL) .glow() - .variable(EnchantingGUI.ENCHANT_FUEL_VAR, 5)); + .variable(EnchantingGui.ENCHANT_FUEL_VAR, 5)); public static final ComplexItem INFUSED_ORBITEX = new ComplexItem(new ItemSettings() .id("infused_orbitex") @@ -350,7 +347,7 @@ public class ItemRegistry { .rarity(ComplexItem.Rarity.UNCOMMON) .type(ComplexItem.Type.ENCHANTING_FUEL) .glow() - .variable(EnchantingGUI.ENCHANT_FUEL_VAR, 15)); + .variable(EnchantingGui.ENCHANT_FUEL_VAR, 15)); public static final ComplexItem CREATIVE_MIND = new ComplexItem((new ItemSettings() .id("creative_mind") @@ -388,50 +385,6 @@ public class ItemRegistry { .stat(Stats.STRENGTH, 50d) .ability(AbilityRegistry.TERRA_STRIKE)); - public static final ComplexItem BURNING_HELMET = new ComplexItem(new ItemSettings() - .id("burning_helmet") - .material(Material.LEATHER_HELMET) - .rarity(ComplexItem.Rarity.RARE) - .type(ComplexItem.Type.HELMET) - .modifier(AttributeRegistry.HEALTH, 5) - .modifier(AttributeRegistry.MOVEMENT_SPEED, 0.05, AttributeModifier.Operation.ADD_SCALAR) - .modifier(AttributeRegistry.ARMOR, 4) - .modifier(AttributeRegistry.ARMOR_TOUGHNESS, 1) - .abilities(AbilityRegistry.ROARING_FLAME)); - - public static final ComplexItem BURNING_CHESTPLATE = new ComplexItem(new ItemSettings() - .id("burning_chestplate") - .material(Material.LEATHER_CHESTPLATE) - .rarity(ComplexItem.Rarity.RARE) - .type(ComplexItem.Type.CHESTPLATE) - .modifier(AttributeRegistry.HEALTH, 12) - .modifier(AttributeRegistry.MOVEMENT_SPEED, 0.05, AttributeModifier.Operation.ADD_SCALAR) - .modifier(AttributeRegistry.ARMOR, 10) - .modifier(AttributeRegistry.ARMOR_TOUGHNESS, 1) - .abilities(AbilityRegistry.ROARING_FLAME)); - - public static final ComplexItem BURNING_LEGGINGS = new ComplexItem(new ItemSettings() - .id("burning_leggings") - .material(Material.LEATHER_LEGGINGS) - .rarity(ComplexItem.Rarity.RARE) - .type(ComplexItem.Type.LEGGINGS) - .modifier(AttributeRegistry.HEALTH, 10) - .modifier(AttributeRegistry.MOVEMENT_SPEED, 0.05, AttributeModifier.Operation.ADD_SCALAR) - .modifier(AttributeRegistry.ARMOR, 8) - .modifier(AttributeRegistry.ARMOR_TOUGHNESS, 1) - .abilities(AbilityRegistry.ROARING_FLAME)); - - public static final ComplexItem BURNING_BOOTS = new ComplexItem(new ItemSettings() - .id("burning_boots") - .material(Material.LEATHER_BOOTS) - .rarity(ComplexItem.Rarity.RARE) - .type(ComplexItem.Type.BOOTS) - .modifier(AttributeRegistry.HEALTH, 5) - .modifier(AttributeRegistry.MOVEMENT_SPEED, 0.05, AttributeModifier.Operation.ADD_SCALAR) - .modifier(AttributeRegistry.ARMOR, 3) - .modifier(AttributeRegistry.ARMOR_TOUGHNESS, 1) - .abilities(AbilityRegistry.ROARING_FLAME, AbilityRegistry.LAVA_GLIDER)); - public static final ComplexItem DARKCALLER = new ComplexItem(new ItemSettings() .id("darkcaller") .material(Material.BEACON) @@ -451,18 +404,6 @@ public class ItemRegistry { .ability(AbilityRegistry.GILDED_CONSUME) .rarity(ComplexItem.Rarity.RARE)); - public static final ComplexItem START_BUTTON = new ComplexItem(new ItemSettings() - .id("start_button") - .material(Material.REDSTONE) - .ability(AbilityRegistry.START_BUTTON) - .rarity(ComplexItem.Rarity.MYTHIC)); - - public static final ComplexItem SOUL_STONE = new ComplexItem(new ItemSettings() - .id("soul_stone") - .material(Material.NETHER_STAR) - .ability(AbilityRegistry.PORTALIZER) - .rarity(ComplexItem.Rarity.MYTHIC)); - public static final ComplexItem ARCANE_JEWEL = new ComplexItem(new ItemSettings() .id("arcane_jewel") .material(Material.AMETHYST_SHARD) @@ -711,7 +652,7 @@ public class ItemRegistry { // Vanilla Items public static final VanillaItem LAPIS_LAZULI = new VanillaItem(new ItemSettings() .material(Material.LAPIS_LAZULI) - .variable(EnchantingGUI.ENCHANT_FUEL_VAR, 1)); + .variable(EnchantingGui.ENCHANT_FUEL_VAR, 1)); public static final ComplexItem VERTEXICAL_BLADE = new ComplexItem(new ItemSettings() .id("vertex_blade") @@ -747,7 +688,7 @@ public class ItemRegistry { @Deprecated public static List registerRecipes() { - for (ComplexItem item : ComplexItem.itemRegistry) { + for (ComplexItem item : ComplexItem.itemRegistry.values()) { registeredRecipes.addAll(item.getRecipes()); } @@ -769,26 +710,4 @@ public static List registerRecipes() { public static void registerItems() { Util.logToConsole(ChatColor.WHITE + "Registering " + ChatColor.GOLD + ComplexItem.itemRegistry.size() + ChatColor.WHITE + " items."); } - - @Nullable - public static ComplexItem byItem(ItemStack item) { - try { - PersistentDataContainer container = Objects.requireNonNull(item.getItemMeta()).getPersistentDataContainer(); - String id = container.get(ComplexItem.GLOBAL_ID, PersistentDataType.STRING); - return byId(id); - } catch (NullPointerException e) { - return null; - } - } - - @Nullable - public static ComplexItem byId(String id) { - for (ComplexItem item : ComplexItem.itemRegistry) { - if (id == null) return null; - if (id.equals(item.getId())) { - return item; - } - } - return null; - } } diff --git a/src/main/java/me/zenox/evocraft/item/ItemSettings.java b/src/main/java/me/zenox/evocraft/item/ItemSettings.java index 3bb25bd..babdffc 100644 --- a/src/main/java/me/zenox/evocraft/item/ItemSettings.java +++ b/src/main/java/me/zenox/evocraft/item/ItemSettings.java @@ -1,6 +1,6 @@ package me.zenox.evocraft.item; -import com.archyx.aureliumskills.stats.Stat; +import dev.aurelium.auraskills.api.stat.Stats; import me.zenox.evocraft.Slot; import me.zenox.evocraft.abilities.Ability; import me.zenox.evocraft.attribute.Attribute; @@ -26,9 +26,9 @@ public class ItemSettings { private ComplexItem.Type type; private Material material; private ItemMeta meta; - private Map stats; + private Map stats; private String skullURL; - private List abilities; + private List> abilities; private HashMap variableMap; private List attributeModifiers; @@ -47,7 +47,7 @@ public ItemSettings() { this.attributeModifiers = new ArrayList<>(); } - public ItemSettings(String id, Boolean unique, Boolean glow, ComplexItem.Rarity rarity, ComplexItem.Type type, Material material, ItemMeta meta, Map stats, String skullURL, List abilities, HashMap variableMap, List attributeModifiers) { + public ItemSettings(String id, Boolean unique, Boolean glow, ComplexItem.Rarity rarity, ComplexItem.Type type, Material material, ItemMeta meta, Map stats, String skullURL, List> abilities, HashMap variableMap, List attributeModifiers) { this.id = id; this.unique = unique; this.glow = glow; @@ -62,7 +62,7 @@ public ItemSettings(String id, Boolean unique, Boolean glow, ComplexItem.Rarity this.attributeModifiers = attributeModifiers; } - public ItemSettings(String id, Boolean unique, Boolean glow, ComplexItem.Rarity rarity, ComplexItem.Type type, Material material, ItemMeta meta, Map stats, String skullURL, List abilities){ + public ItemSettings(String id, Boolean unique, Boolean glow, ComplexItem.Rarity rarity, ComplexItem.Type type, Material material, ItemMeta meta, Map stats, String skullURL, List> abilities){ this(id, unique, glow, rarity, type, material, meta, stats, skullURL, abilities, new HashMap<>(), new ArrayList<>()); } @@ -105,7 +105,7 @@ public ItemMeta getMeta() { return meta; } - public Map getStats() { + public Map getStats() { return stats; } @@ -113,7 +113,7 @@ public String getSkullURL() { return skullURL; } - public List getAbilities() { + public List> getAbilities() { return abilities; } @@ -179,12 +179,12 @@ public ItemSettings attribute(org.bukkit.attribute.Attribute attribute, org.bukk return this; } - public ItemSettings stats(Map stats) { + public ItemSettings stats(Map stats) { this.stats = stats; return this; } - public ItemSettings stat(Stat stat, Double num) { + public ItemSettings stat(Stats stat, Double num) { Attribute attr; try { attr = ((Attribute) Attribute.attributeRegistry.stream() @@ -206,22 +206,22 @@ public ItemSettings skullURL(String skullURL) { return this; } - public ItemSettings abilities(List abilities) { + public ItemSettings abilities(List> abilities) { this.abilities = abilities; return this; } - public ItemSettings abilities(Ability... abilities) { + public ItemSettings abilities(Ability... abilities) { this.abilities = List.of(abilities); return this; } - public ItemSettings addAbilities(Ability... abilities) { + public ItemSettings addAbilities(Ability... abilities) { this.abilities.addAll(List.of(abilities)); return this; } - public ItemSettings ability(Ability ability) { + public ItemSettings ability(Ability ability) { this.abilities.add(ability); return this; } diff --git a/src/main/java/me/zenox/evocraft/item/VanillaItem.java b/src/main/java/me/zenox/evocraft/item/VanillaItem.java index 07af797..61ed918 100644 --- a/src/main/java/me/zenox/evocraft/item/VanillaItem.java +++ b/src/main/java/me/zenox/evocraft/item/VanillaItem.java @@ -6,6 +6,7 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -83,7 +84,7 @@ public VanillaItem(Material material) { * Vanilla item constructor to override the default settings of a vanilla item. * @param settings The settings to override. */ - public VanillaItem(ItemSettings settings) { + public VanillaItem(@NotNull ItemSettings settings) { super(settings.id(settings.getMaterial().getKey().getKey()), true); if (!settings.getMaterial().isItem()) throw new IllegalArgumentException("Material must have an item form"); for (VanillaItem item : new ArrayList<>(vanillaItemList)) { diff --git a/src/main/java/me/zenox/evocraft/item/basicitems/CorruptPearl.java b/src/main/java/me/zenox/evocraft/item/basicitems/CorruptPearl.java index 90fb4f4..b34ac06 100644 --- a/src/main/java/me/zenox/evocraft/item/basicitems/CorruptPearl.java +++ b/src/main/java/me/zenox/evocraft/item/basicitems/CorruptPearl.java @@ -3,7 +3,6 @@ import me.zenox.evocraft.EvoCraft; import me.zenox.evocraft.item.ComplexItem; -import me.zenox.evocraft.persistence.SerializedPersistentType; import org.bukkit.*; import org.bukkit.entity.Enderman; import org.bukkit.entity.EntityType; @@ -12,6 +11,7 @@ import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; import java.util.List; import java.util.Map; @@ -49,11 +49,11 @@ public void dropEvent(EntityDeathEvent event) { Enderman specialEnderman = (Enderman) w.spawnEntity(loc.clone().add(Math.sin(r.nextDouble(2) * Math.PI) * r.nextDouble(2), 1, Math.sin(r.nextDouble(2) * Math.PI) * r.nextDouble(2)), EntityType.ENDERMAN); specialEnderman.setCarriedBlock(Material.END_PORTAL_FRAME.createBlockData()); - specialEnderman.getPersistentDataContainer().set(new NamespacedKey(EvoCraft.getPlugin(), "corrupted"), new SerializedPersistentType<>(), true); + specialEnderman.getPersistentDataContainer().set(new NamespacedKey(EvoCraft.getPlugin(), "corrupted"), PersistentDataType.BOOLEAN, true); } - boolean isCorrupted = entity.getPersistentDataContainer().has(new NamespacedKey(EvoCraft.getPlugin(), "corrupted"), new SerializedPersistentType<>()) ? - entity.getPersistentDataContainer().get(new NamespacedKey(EvoCraft.getPlugin(), "corrupted"), new SerializedPersistentType<>()) : false; + boolean isCorrupted = entity.getPersistentDataContainer().has(new NamespacedKey(EvoCraft.getPlugin(), "corrupted"), PersistentDataType.BOOLEAN) ? + entity.getPersistentDataContainer().get(new NamespacedKey(EvoCraft.getPlugin(), "corrupted"), PersistentDataType.BOOLEAN) : false; if (isCorrupted) { event.getDrops().removeIf((ItemStack item) -> item.getType().equals(Material.END_PORTAL_FRAME)); w.dropItemNaturally(loc, CORRUPT_PEARL.getItemStack(1)); diff --git a/src/main/java/me/zenox/evocraft/item/basicitems/GardenerSapling.java b/src/main/java/me/zenox/evocraft/item/basicitems/GardenerSapling.java deleted file mode 100644 index d3608de..0000000 --- a/src/main/java/me/zenox/evocraft/item/basicitems/GardenerSapling.java +++ /dev/null @@ -1,30 +0,0 @@ -package me.zenox.evocraft.item.basicitems; - -import me.zenox.evocraft.item.ComplexItem; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemFlag; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class GardenerSapling extends ComplexItem { - public GardenerSapling() { - super("gardener_sapling", Rarity.VERY_SPECIAL, Type.MISC, Material.OAK_SAPLING, Map.of()); - - List lore = new ArrayList<>(); - lore.add(ChatColor.GRAY + "A sapling, that can when cared for"); - lore.add(ChatColor.GRAY + "can grow into something beautiful."); - lore.add(""); - lore.add(ChatColor.GRAY + "A thanks to the beta testers who helped along the way."); - lore.add(""); - lore.add(ChatColor.GRAY + "Issued to: " + ChatColor.YELLOW + "%s"); - lore.add(ChatColor.GRAY + "Issued From: " + ChatColor.YELLOW + "%s"); - lore.add(ChatColor.GRAY + "Date Issued: " + ChatColor.YELLOW + "%s"); - this.getMeta().setLore(lore); - this.getMeta().addEnchant(Enchantment.DAMAGE_ALL, 1, true); - this.getMeta().addItemFlags(ItemFlag.HIDE_ENCHANTS); - } -} diff --git a/src/main/java/me/zenox/evocraft/recipe/ComplexChoice.java b/src/main/java/me/zenox/evocraft/recipe/ComplexChoice.java index 8e4bd8d..a63d028 100644 --- a/src/main/java/me/zenox/evocraft/recipe/ComplexChoice.java +++ b/src/main/java/me/zenox/evocraft/recipe/ComplexChoice.java @@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableMap; import me.zenox.evocraft.item.ComplexItem; import me.zenox.evocraft.item.ComplexItemStack; -import me.zenox.evocraft.item.ItemRegistry; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.RecipeChoice; import org.jetbrains.annotations.NotNull; @@ -39,7 +38,8 @@ public ComplexChoice(@NotNull Map choices) { @NotNull @Override public ItemStack getItemStack() { - return new ComplexItemStack(ItemRegistry.byId(((Map.Entry) choices.entrySet().toArray()[0]).getKey()), ((Map.Entry) choices.entrySet().toArray()[0]).getValue()).getItem(); + return new ComplexItemStack(ComplexItem.itemRegistry.get(((Map.Entry) choices.entrySet().toArray()[0]).getKey()), + ((Map.Entry) choices.entrySet().toArray()[0]).getValue()).getItem(); } public Map getChoices() { @@ -60,7 +60,7 @@ public ComplexChoice clone() { @Override public boolean test(@NotNull ItemStack t) { for (Map.Entry match : choices.entrySet()) { - if (ComplexItemStack.of(t).getComplexItem().equals(match.getKey()) && (t.getAmount() == match.getValue() || match.getValue() == -1)) { + if (ComplexItem.of(t).equals(match.getKey()) && (t.getAmount() == match.getValue() || match.getValue() == -1)) { return true; } } diff --git a/src/main/java/me/zenox/evocraft/story/Action.java b/src/main/java/me/zenox/evocraft/story/Action.java deleted file mode 100644 index 69f3e99..0000000 --- a/src/main/java/me/zenox/evocraft/story/Action.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.zenox.evocraft.story; - -import org.bukkit.event.Event; - -public class Action{ - -} diff --git a/src/main/java/me/zenox/evocraft/story/Chapter.java b/src/main/java/me/zenox/evocraft/story/Chapter.java deleted file mode 100644 index 035117c..0000000 --- a/src/main/java/me/zenox/evocraft/story/Chapter.java +++ /dev/null @@ -1,70 +0,0 @@ -package me.zenox.evocraft.story; - -import me.zenox.evocraft.EvoCraft; -import me.zenox.evocraft.data.TranslatableText; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.Listener; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -/** - * A chapter is a part of the story. It is a collection of actions that are executed when the chapter starts and ends. - * @param The event that triggers the chapter. - * @param The event that triggers the end of the chapter (the event that triggers the next chapter). - */ -public abstract class Chapter implements Listener { - private final int id; - private final TranslatableText name; - /** - * Whether the chapter is a "solo" chapter. A solo chapter is a chapter that the player has to perform alone, without any other players, hiding them from all other players. - */ - private final boolean solo; - - public Chapter(int id, boolean solo) { - this.id = id; - this.name = new TranslatableText("chapter-" + id); - this.solo = solo; - } - - private Type getType(int index) { - Class clazz = getClass(); - while (clazz != null) { - Type type = clazz.getGenericSuperclass(); - if (type instanceof ParameterizedType) { - return ((ParameterizedType) type).getActualTypeArguments()[index]; - } - clazz = clazz.getSuperclass(); - } - return null; - } - - /** - * Method that detects when a chapter should start and executes - */ - public abstract void onChapterStart(T event); - - /** - * Method that executes when a chapter ends - */ - public abstract void onChapterEnd(U event); - - public void progress(Player player, U event) { - EvoCraft.getChapterManager().setChapter(player, id + 1); - onChapterEnd(event); - EvoCraft.getChapterManager().getChapter(id + 1).onChapterStart(event); - } - - public int getId() { - return id; - } - - public TranslatableText getName() { - return name; - } - - public boolean isSolo() { - return solo; - } -} diff --git a/src/main/java/me/zenox/evocraft/story/ChapterManager.java b/src/main/java/me/zenox/evocraft/story/ChapterManager.java deleted file mode 100644 index 7f8281c..0000000 --- a/src/main/java/me/zenox/evocraft/story/ChapterManager.java +++ /dev/null @@ -1,109 +0,0 @@ -package me.zenox.evocraft.story; - -import me.zenox.evocraft.EvoCraft; -import me.zenox.evocraft.story.chapters.ChapterOne; -import me.zenox.evocraft.story.chapters.ChapterTwo; -import me.zenox.evocraft.story.chapters.ChapterZero; -import me.zenox.evocraft.util.Util; -import org.bukkit.Bukkit; -import org.bukkit.NamespacedKey; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.persistence.PersistentDataType; -import org.bukkit.scheduler.BukkitRunnable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -public class ChapterManager implements Listener { - public static NamespacedKey CHAPTER_KEY = new NamespacedKey(EvoCraft.getPlugin(), "chapter"); - - private EvoCraft plugin; - - public List chapters = new ArrayList<>(); - - static { - // Runnable that hides players for solo chapters - new BukkitRunnable(){ - @Override - public void run() { - ChapterManager manager = EvoCraft.getPlugin().getChapterManager(); - for(Player p : Bukkit.getOnlinePlayers()){ - try { - if (manager.getChapter(p).isSolo()) { - for (Player p2 : Bukkit.getOnlinePlayers()) { - if (p != p2) { - p.hidePlayer(EvoCraft.getPlugin(), p2); - if (!p2.getEffectivePermissions().contains("evocraft.admin")) - p2.hidePlayer(EvoCraft.getPlugin(), p); - } - } - } else { - for (Player p2 : Bukkit.getOnlinePlayers()) { - p.showPlayer(EvoCraft.getPlugin(), p2); - p2.showPlayer(EvoCraft.getPlugin(), p); - } - } - } catch (NullPointerException e){ - Util.logToConsole("Player " + p.getName() + " has no chapter data!"); - manager.setChapter(p, manager.getChapter(2)); - //p.kickPlayer("You have no chapter data! Please rejoin."); - } - } - } - }.runTaskTimer(EvoCraft.getPlugin(), 1, 10); - } - - public ChapterManager(EvoCraft plugin) { - this.plugin = plugin; - registerChapters(); - Bukkit.getPluginManager().registerEvents(this, plugin); - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - Chapter chapter = getChapter(player); - Util.logToConsole("Player " + player.getName() + " joined with chapter " + chapter.getId()); - if(chapter == null) { - chapter = ChapterZero.getInstance(); - player.getPersistentDataContainer().set(CHAPTER_KEY, PersistentDataType.INTEGER, chapter.getId()); - } - - if(chapter.equals(ChapterZero.getInstance())) chapter.onChapterStart(event); - } - - @Nullable - public Chapter getChapter(@NotNull Player player){ - return player.getPersistentDataContainer().has(CHAPTER_KEY, PersistentDataType.INTEGER) ? chapters.get(player.getPersistentDataContainer().get(CHAPTER_KEY, PersistentDataType.INTEGER)) : null; - } - - @Nullable - public Chapter getChapter(int id){ - return chapters.get(id); - } - - public void setChapter(Player p, Chapter chapter){ - p.getPersistentDataContainer().set(CHAPTER_KEY, PersistentDataType.INTEGER, chapter.getId()); - } - - public void setChapter(Player p, int id){ - Util.sendMessage(p, "Setting chapter of player %s to %s.".formatted(p.getName(), id)); - try{ - setChapter(p, chapters.get(id)); - } catch (IndexOutOfBoundsException e){ - throw(new IndexOutOfBoundsException("Chapter with id " + id + " does not exist!")); - } - } - - public void registerChapters() { - // Register all chapters here - chapters.add(ChapterZero.getInstance()); - chapters.add(ChapterOne.getInstance()); - chapters.add(ChapterTwo.getInstance()); - } -} diff --git a/src/main/java/me/zenox/evocraft/story/chapters/ChapterOne.java b/src/main/java/me/zenox/evocraft/story/chapters/ChapterOne.java deleted file mode 100644 index b88748f..0000000 --- a/src/main/java/me/zenox/evocraft/story/chapters/ChapterOne.java +++ /dev/null @@ -1,35 +0,0 @@ -package me.zenox.evocraft.story.chapters; - -import me.zenox.evocraft.story.Chapter; -import me.zenox.evocraft.util.Romans; -import me.zenox.evocraft.util.Util; -import org.bukkit.Location; -import org.bukkit.Sound; -import org.bukkit.event.player.PlayerInteractEvent; - -public class ChapterOne extends Chapter { - - private static ChapterOne instance = null; - - private ChapterOne() { - super(1, true); - } - - @Override - public void onChapterStart(PlayerInteractEvent event) { - Util.sendTitle(event.getPlayer(), "&b&lChapter " + Romans.encode(this.getId()), "&lThe Guardian's Keep", 10, 40, 10); - event.getPlayer().teleport(new Location(event.getPlayer().getServer().getWorld("flat"), -346, -54, -510)); - event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 0.5f, 0.8f); - // Begin Voiceover - event.getPlayer().playSound(event.getPlayer().getLocation(), "story.chapter.1.backstory_1", 20f, 1f); - } - - @Override - public void onChapterEnd(PlayerInteractEvent event) { - } - - public static ChapterOne getInstance() { - if(instance == null) instance = new ChapterOne(); - return instance; - } -} diff --git a/src/main/java/me/zenox/evocraft/story/chapters/ChapterTwo.java b/src/main/java/me/zenox/evocraft/story/chapters/ChapterTwo.java deleted file mode 100644 index ad3ed6e..0000000 --- a/src/main/java/me/zenox/evocraft/story/chapters/ChapterTwo.java +++ /dev/null @@ -1,37 +0,0 @@ -package me.zenox.evocraft.story.chapters; - -import me.zenox.evocraft.story.Chapter; -import me.zenox.evocraft.util.Romans; -import me.zenox.evocraft.util.Util; -import org.bukkit.Location; -import org.bukkit.Sound; -import org.bukkit.event.player.PlayerInteractEvent; - -public class ChapterTwo extends Chapter { - private static ChapterTwo instance = null; - - private ChapterTwo() { - super(2, false); - } - - @Override - public void onChapterStart(PlayerInteractEvent event) { - Util.sendTitle(event.getPlayer(), "&b&lChapter " + Romans.encode(this.getId()), "&lHumble Beginnings", 10, 40, 10); - event.getPlayer().teleport(new Location(event.getPlayer().getServer().getWorld("flat"), -134, 78, -466)); - event.getPlayer().setBedSpawnLocation(new Location(event.getPlayer().getServer().getWorld("flat"), -134, 78, -466), true); - event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.BLOCK_PORTAL_TRAVEL, 1, 1.5f); - Util.sendMessage(event.getPlayer(), "&b&lQUICK TIP: &fExplore the island! Head to the portal at the center of the island once you would like to begin your adventure."); - - } - - @Override - public void onChapterEnd(PlayerInteractEvent event) { - // Clear the player's inventory - event.getPlayer().getInventory().clear(); - } - - public static ChapterTwo getInstance() { - if(instance == null) instance = new ChapterTwo(); - return instance; - } -} diff --git a/src/main/java/me/zenox/evocraft/story/chapters/ChapterZero.java b/src/main/java/me/zenox/evocraft/story/chapters/ChapterZero.java deleted file mode 100644 index 50b2931..0000000 --- a/src/main/java/me/zenox/evocraft/story/chapters/ChapterZero.java +++ /dev/null @@ -1,41 +0,0 @@ -package me.zenox.evocraft.story.chapters; - -import me.zenox.evocraft.item.ComplexItemStack; -import me.zenox.evocraft.item.ItemRegistry; -import me.zenox.evocraft.story.Chapter; -import me.zenox.evocraft.util.Util; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; - -public class ChapterZero extends Chapter { - - private static ChapterZero instance = null; - - private ChapterZero() { - super(0, true); - } - - @Override - public void onChapterStart(PlayerJoinEvent event) { - Player player = event.getPlayer(); - player.teleport(new Location(event.getPlayer().getServer().getWorld("flat"), -367, 17, -593)); - Util.sendTitle(player, "&b&lChapter Ω", "&d&lPress Start", 10, 150, 10); - Util.sendMessage(player, "&eNote: &bEvoCraft &fis best experienced with sounds turned on. If you have sounds turned off, you may miss elemental effects, voiceovers, and other important sounds."); - player.getInventory().setHeldItemSlot(4); - player.getInventory().setItem(4, new ComplexItemStack(ItemRegistry.START_BUTTON).getItem()); - } - - @Override - public void onChapterEnd(PlayerInteractEvent event) { - // Clear the player's inventory - event.getPlayer().getInventory().clear(); - } - - public static ChapterZero getInstance() { - if(instance == null) instance = new ChapterZero(); - return instance; - } -} - diff --git a/src/main/java/me/zenox/evocraft/util/Geo.java b/src/main/java/me/zenox/evocraft/util/GeometryUtils.java similarity index 98% rename from src/main/java/me/zenox/evocraft/util/Geo.java rename to src/main/java/me/zenox/evocraft/util/GeometryUtils.java index 0f134f5..bdd097d 100644 --- a/src/main/java/me/zenox/evocraft/util/Geo.java +++ b/src/main/java/me/zenox/evocraft/util/GeometryUtils.java @@ -5,7 +5,7 @@ import java.util.ArrayList; import java.util.List; -public class Geo { +public class GeometryUtils { /// Generates a list of vertices (in arbitrary order) for a tetrahedron centered on the origin. public static List makeDodecahedron(Vector vec, double r) { diff --git a/src/main/java/me/zenox/evocraft/util/Util.java b/src/main/java/me/zenox/evocraft/util/Util.java index fd7ca4d..4ce3df2 100644 --- a/src/main/java/me/zenox/evocraft/util/Util.java +++ b/src/main/java/me/zenox/evocraft/util/Util.java @@ -1,13 +1,11 @@ package me.zenox.evocraft.util; -import com.archyx.aureliumskills.AureliumSkills; -import com.archyx.aureliumskills.modifier.ModifierType; -import com.archyx.aureliumskills.modifier.Modifiers; -import com.archyx.aureliumskills.modifier.StatModifier; -import com.archyx.aureliumskills.stats.Stat; -import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import me.zenox.evocraft.EvoCraft; +import com.destroystokyo.paper.profile.PlayerProfile; +import com.destroystokyo.paper.profile.ProfileProperty; +import dev.aurelium.auraskills.api.AuraSkillsApi; +import dev.aurelium.auraskills.api.user.SkillsUser; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; @@ -17,7 +15,6 @@ import org.bukkit.inventory.meta.SkullMeta; import org.jetbrains.annotations.NotNull; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -43,7 +40,11 @@ public static void sendMessage(@NotNull CommandSender p, String message, boolean } public static void sendActionBar(@NotNull Player p, String message) { - EvoCraft.getActionBar().sendAbilityActionBar(p, ChatColor.translateAlternateColorCodes('&', message)); + AuraSkillsApi.get().getUserManager().getUser(p.getUniqueId()).sendActionBar(ChatColor.translateAlternateColorCodes('&', message)); + } + + public static void sendActionBar(@NotNull Player p, Component message) { + AuraSkillsApi.get().getUserManager().getUser(p.getUniqueId()).sendActionBar( LegacyComponentSerializer.legacySection().serialize(message)); } public static void sendTitle(@NotNull Player p, String title, String subtitle, int fadeIn, int stay, int fadeOut) { @@ -74,15 +75,9 @@ public static ItemStack makeSkull(@NotNull ItemStack item, String base64EncodedS r.nextBytes(array); UUID id = UUID.nameUUIDFromBytes(array); - GameProfile profile = new GameProfile(id, null); - profile.getProperties().put("textures", new Property("textures", base64EncodedString)); - try { - Field profileField = meta.getClass().getDeclaredField("profile"); - profileField.setAccessible(true); - profileField.set(meta, profile); - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - } + PlayerProfile profile = Bukkit.createProfile(id, null); + profile.getProperties().add(new ProfileProperty("textures", base64EncodedString)); + meta.setPlayerProfile(profile); item.setItemMeta(meta); return item; } @@ -104,9 +99,9 @@ public static UUID constantUUID(String str){ /** * Gets nearby blocks given a radius and location * @param loc The location - * @param radius The radius - * @param yradius The y radius - * @return + * @param radius The radius in the orthogonal horizontal directions + * @param yradius The radius in the y direction + * @return the list of blocks */ public static List getNearbyBlocks(Location loc, int radius, int yradius) { List nearbyBlocks = new ArrayList(); @@ -129,29 +124,6 @@ public static boolean isInvulnerable(Entity entity){ return (entity.hasMetadata("NPC") || (entity instanceof Player player && player.getGameMode() == GameMode.CREATIVE)); } - /** - * Gets all the modifiers an item has - * @param item the item to check - * @param type the type of modifier to check - * @return the list of modifiers - */ - public static List getAureliumModifiers(ItemStack item, ModifierType type){ - Modifiers modifiers = new Modifiers(AureliumSkills.getPlugin(AureliumSkills.class)); - return modifiers.getModifiers(type, item); - } - - /** - * Removes all modifiers of a certain type from an item - * @param item the item to remove the modifiers from - * @param type the type of modifiers to remove - * @param stat the stat to remove the modifiers from - * @return the item with the modifiers removed - */ - public static ItemStack removeAureliumModifier(ItemStack item, ModifierType type, Stat stat){ - Modifiers modifiers = new Modifiers(AureliumSkills.getPlugin(AureliumSkills.class)); - return modifiers.removeModifier(type, item, stat); - } - /** * Rounds a given double to the specified number of decimal places. * @param value the value to round @@ -162,4 +134,10 @@ public static double round(double value, int digits) { double factor = Math.pow(10, digits); return Math.round(value * factor) / factor; } + + private static final AuraSkillsApi api = AuraSkillsApi.get(); + + public static SkillsUser getSkillsUser(Player player) { + return api.getUser(player.getUniqueId()); + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e41ef3c..3df492b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -4,4 +4,6 @@ force_update_default: true # Locale -locale: en_US \ No newline at end of file +locale: en_US + +autosave-minutes: 5 \ No newline at end of file diff --git a/src/main/resources/languages/en_US.yml b/src/main/resources/languages/en_US.yml index 21b14e0..6477b2d 100644 --- a/src/main/resources/languages/en_US.yml +++ b/src/main/resources/languages/en_US.yml @@ -638,6 +638,18 @@ ability-name-rapid_fire: Rapid Fire ability-lore-rapid_fire: - "Fire instantly." +########################################################################## +## CLASS ABILITIES ## +########################################################################## +ability-name-mage_teleport: Teleport +ability-name-mage_mana_ball: Mana Ball +ability-name-mage_rift_beam: Rift Beam +ability-name-mage_rune_shield: Rune Shield + +ability-name-warrior_bloodlust: Bloodlust +ability-name-warrior_triple_slash: Triple Slash +ability-name-warrior_bull_rush: Triple Slash +ability-name-warrior_counterstrike: Triple Slash ########################################################################## ## ENCHANTMENTS ## ########################################################################## @@ -712,6 +724,85 @@ gui-enchant-action-lore-3: - "" - "&c&nRequires enchanting level 25!" +gui-class-action-title-mage: "&b&lMage &7→ &eClick to Select" +gui-class-action-lore-mage: + - "&fHarness the power of &bmana&f and &bmagic&f." + - "" + - "&7Weapons: &fStaffs, Wands, Potions" + - "" + - "&7Subclasses: " + - "&eRunecaster, Arcanist, Lightweaver" + - "" + - "&8(Low health, high damage, medium speed)" + +gui-class-action-title-warrior: "&c&lWarrior &7→ &eClick to Select" +gui-class-action-lore-warrior: + - "&fA mobile melee combatant," + - "excelling in close quarters." + - "" + - "&7Weapons: &fSwords, Axes" + - "" + - "&7Subclasses: " + - "&eGladiator, Rogue, Bladestorm" + - "" + - "&8(Fast, agile, low health siphon)" + +gui-class-action-title-tank: "&a&lTank &7→ &eClick to Select" +gui-class-action-lore-tank: + - "&fBecome the shield of your team," + - "&fand deal massive blows." + - "" + - "&7Weapons: &fMaces, Greatswords, Hammers" + - "" + - "&7Subclasses: " + - "&eStoneheart, Warden, Centurion" + - "" + - "&8(High health, slower, high damage)" + +gui-class-action-title-archer: "&6&lArcher &7→ &eClick to Select" +gui-class-action-lore-archer: + - "&fMaster the art of ranged combat," + - "&fand deal damage from afar." + - "" + - "&7Weapons: &fBows, Blasters" + - "" + - "&7Subclasses: " + - "&eDeadeye, Skirmisher, Fusillade" + - "" + - "&8(Medium health, good speed, medium damage)" + +########################################################################## +## CLASSES ## +########################################################################## +class-name-mage: "&b&lMage" +class-desc-mage: + - "&7Harness the mystical arts and control the battlefield with your spells." + - "&7Wield powerful &fStaffs, Wands &7and craft potent &fPotions." + - "&8Subclasses: &eRunecaster, Arcanist, Lightweaver" + - "&8(Low health, high damage, medium speed)" + +class-name-warrior: "&c&lWarrior" +class-desc-warrior: + - "&7Engage in close combat with agility and precision." + - "&7Brandish deadly &fSwords &7and swift &fAxes." + - "&8Subclasses: &eGladiator, Rogue, Bladestorm" + - "&8(Fast, agile, low health siphon)" + +class-name-tank: "&a&lTank" +class-desc-tank: + - "&7Hold the front line and protect your allies with might." + - "&7Swing devastating &fMaces, Greatswords &7and crushing &fHammers." + - "&8Subclasses: &eStoneheart, Warden, Centurion" + - "&8(High health, slower, high damage)" + +class-name-archer: "&6&lArcher" +class-desc-archer: + - "&7Take down foes from a distance, mastering the bow's art." + - "&7Equip versatile &fBows &7and modern &fBlasters." + - "&8Subclasses: &eDeadeye, Skirmisher, Fusillade" + - "&8(Medium health, good speed, medium damage)" + + ########################################################################## ## ATTRIBUTES ## ########################################################################## diff --git a/src/main/resources/playerdata.yml b/src/main/resources/playerdata.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 6368357..3cdd851 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: EvoCraft version: '${project.version}' main: me.zenox.evocraft.EvoCraft -api-version: 1.19 +api-version: 1.20 authors: [ ZenoX ] description: Transforms your game into an highly specialized MMORPG experience. softdepend: [ Citizens, WorldGuard, WorldEdit ]