getDrops() {
+ return drops;
+ }
- public BlockInfo getBlockInfo() {
- return info;
- }
+ public BlockInfo getBlockInfo() {
+ return info;
+ }
- @Deprecated
- public boolean canBreak() {
- return canBreak;
- }
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
- @Deprecated
- public void setCanBreak(boolean value) {
- canBreak = value;
- }
+ @Override
+ public void setCancelled(boolean value) {
+ cancelled = value;
+ }
- @Override
- public boolean isCancelled() {
- return cancelled;
- }
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
- @Override
- public void setCancelled(boolean value) {
- cancelled = value;
- }
-
- @Override
- public HandlerList getHandlers() {
- return handlers;
- }
-
- public static HandlerList getHandlerList() {
- return handlers;
- }
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerPostCastSkillEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerPostCastSkillEvent.java
index 8270e463..8f3147bd 100644
--- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerPostCastSkillEvent.java
+++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerPostCastSkillEvent.java
@@ -1,15 +1,15 @@
package net.Indyuce.mmocore.api.event;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
-import net.Indyuce.mmocore.api.skill.SkillResult;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
import org.bukkit.event.HandlerList;
public class PlayerPostCastSkillEvent extends PlayerDataEvent {
private static final HandlerList handlers = new HandlerList();
private final SkillInfo skill;
- private final SkillResult result;
+ private final SkillMetadata result;
/**
* Called right after a player casts a skill.
@@ -18,7 +18,7 @@ public class PlayerPostCastSkillEvent extends PlayerDataEvent {
* @param skill Skill being cast
* @param result SKill casting result
*/
- public PlayerPostCastSkillEvent(PlayerData playerData, SkillInfo skill, SkillResult result) {
+ public PlayerPostCastSkillEvent(PlayerData playerData, SkillInfo skill, SkillMetadata result) {
super(playerData);
this.skill = skill;
@@ -29,7 +29,7 @@ public class PlayerPostCastSkillEvent extends PlayerDataEvent {
return skill;
}
- public SkillResult getResult() {
+ public SkillMetadata getResult() {
return result;
}
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerPreCastSkillEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerPreCastSkillEvent.java
index 19f48876..4bbc45db 100644
--- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerPreCastSkillEvent.java
+++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerPreCastSkillEvent.java
@@ -1,7 +1,7 @@
package net.Indyuce.mmocore.api.event;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerResourceUpdateEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerResourceUpdateEvent.java
index 61d6b4fb..a364a43f 100644
--- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerResourceUpdateEvent.java
+++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerResourceUpdateEvent.java
@@ -2,6 +2,7 @@ package net.Indyuce.mmocore.api.event;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
+import net.Indyuce.mmocore.skill.list.Neptune_Gift;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
@@ -27,7 +28,7 @@ public class PlayerResourceUpdateEvent extends PlayerDataEvent implements Cancel
* Called when a player gains some resource back. This can
* be used to handle stats like health or mana regeneration.
*
- * Example use: {@link net.Indyuce.mmocore.skill.Neptune_Gift} which is a skill
+ * Example use: {@link Neptune_Gift} which is a skill
* that temporarily increases resource regeneration for a short amount of time.
*
* @param playerData Player regenerating
diff --git a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
index b6bc9b7f..c43bc896 100644
--- a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
+++ b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
@@ -23,6 +23,7 @@ import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
import net.Indyuce.mmocore.listener.SpellCast.SkillCasting;
import net.Indyuce.mmocore.manager.SoundManager;
+import net.Indyuce.mmocore.skill.CasterMetadata;
import net.Indyuce.mmocore.skill.PlayerSkillData;
import net.Indyuce.mmocore.skill.Skill;
import net.Indyuce.mmocore.skill.Skill.SkillInfo;
@@ -819,7 +820,8 @@ public class PlayerData extends OfflinePlayerData {
return new SkillMetadata(this, skill, CancelReason.OTHER);
// Check for mana/stamina/cooldown and cast skill
- SkillMetadata cast = skill.getSkill().whenCast(this, skill);
+ CasterMetadata casterMeta = new CasterMetadata(this);
+ SkillMetadata cast = skill.getSkill().whenCast(casterMeta, skill);
// Send failure messages
if (!cast.isSuccessful()) {
diff --git a/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java b/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java
index aa9ab37e..75617547 100644
--- a/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java
+++ b/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java
@@ -14,8 +14,8 @@ import net.Indyuce.mmocore.api.player.profess.resource.ManaDisplayOptions;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.profess.resource.ResourceHandler;
import net.Indyuce.mmocore.api.player.stats.StatType;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.api.util.math.particle.CastingParticle;
diff --git a/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java b/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java
index 9d503eb8..3f37599c 100644
--- a/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java
+++ b/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java
@@ -13,7 +13,7 @@ import com.google.gson.JsonObject;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
-import net.Indyuce.mmocore.api.skill.Skill;
+import net.Indyuce.mmocore.skill.Skill;
import net.Indyuce.mmocore.manager.data.PlayerDataManager.DefaultPlayerData;
public class SavedClassInformation {
diff --git a/src/main/java/net/Indyuce/mmocore/api/player/profess/event/trigger/AttackEventTrigger.java b/src/main/java/net/Indyuce/mmocore/api/player/profess/event/trigger/AttackEventTrigger.java
index 676c3c98..7df652ea 100644
--- a/src/main/java/net/Indyuce/mmocore/api/player/profess/event/trigger/AttackEventTrigger.java
+++ b/src/main/java/net/Indyuce/mmocore/api/player/profess/event/trigger/AttackEventTrigger.java
@@ -1,33 +1,32 @@
package net.Indyuce.mmocore.api.player.profess.event.trigger;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-
+import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import io.lumine.mythic.lib.damage.DamageType;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.profess.event.EventTriggerHandler;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
public class AttackEventTrigger implements EventTriggerHandler {
- @Override
- public boolean handles(String event) {
- return event.endsWith("-damage");
- }
+ @Override
+ public boolean handles(String event) {
+ return event.endsWith("-damage");
+ }
- @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
- public void a(PlayerAttackEvent event) {
- // We don't want players dying by themselves when using an enderpearl.
- if(event.getPlayer().equals(event.getEntity())) return;
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void a(PlayerAttackEvent event) {
+ // We don't want players dying by themselves when using an enderpearl.
+ if (event.getPlayer().equals(event.getEntity())) return;
- PlayerData player = PlayerData.get(event.getData().getUniqueId());
- PlayerClass profess = player.getProfess();
+ PlayerData player = PlayerData.get(event.getData().getUniqueId());
+ PlayerClass profess = player.getProfess();
- for (DamageType type : event.getAttack().getTypes()) {
- String path = type.getPath() + "-damage";
- if (profess.hasEventTriggers(path))
- profess.getEventTriggers(path).getTriggers().forEach(trigger -> trigger.apply(player));
- }
- }
+ for (DamageType type : event.getAttack().getDamage().collectTypes()) {
+ String path = type.getPath() + "-damage";
+ if (profess.hasEventTriggers(path))
+ profess.getEventTriggers(path).getTriggers().forEach(trigger -> trigger.apply(player));
+ }
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/api/skill/SkillResult.java b/src/main/java/net/Indyuce/mmocore/api/skill/SkillResult.java
deleted file mode 100644
index 7f0dea1e..00000000
--- a/src/main/java/net/Indyuce/mmocore/api/skill/SkillResult.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package net.Indyuce.mmocore.api.skill;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
-import net.Indyuce.mmocore.comp.flags.FlagPlugin.CustomFlag;
-
-public class SkillResult {
- private final SkillInfo skill;
- private final int level;
- private final double mana, cooldown, stamina;
-
- private CancelReason cancelReason;
-
- public SkillResult(PlayerData data, SkillInfo skill) {
- this.skill = skill;
-
- level = data.getSkillLevel(skill.getSkill());
- cooldown = (skill.getSkill().hasModifier("cooldown") ? data.getSkillData().getCooldown(skill) : 0);
- mana = (skill.getSkill().hasModifier("mana") ? skill.getModifier("mana", level) : 0);
- stamina = (skill.getSkill().hasModifier("stamina") ? skill.getModifier("stamina", level) : 0);
- cancelReason = !data.hasSkillUnlocked(skill) ? CancelReason.LOCKED
- : cooldown > 0 ? CancelReason.COOLDOWN
- : mana > data.getMana() ? CancelReason.MANA
- : stamina > data.getStamina() ? CancelReason.STAMINA
- : !MMOCore.plugin.flagPlugin.isFlagAllowed(data.getPlayer(), CustomFlag.SKILLS)
- ? CancelReason.FLAG
- : null;
- }
-
- public SkillResult(PlayerData data, SkillInfo skill, CancelReason reason) {
- this.skill = skill;
- this.cancelReason = reason;
-
- level = data.getSkillLevel(skill.getSkill());
- cooldown = skill.getSkill().hasModifier("cooldown") ? data.getSkillData().getCooldown(skill) : 0;
- mana = skill.getSkill().hasModifier("mana") ? skill.getModifier("mana", level) : 0;
- stamina = (skill.getSkill().hasModifier("stamina") ? skill.getModifier("stamina", level) : 0);
- }
-
- public Skill getSkill() {
- return skill.getSkill();
- }
-
- public SkillInfo getInfo() {
- return skill;
- }
-
- public int getLevel() {
- return level;
- }
-
- public double getStaminaCost() {
- return stamina;
- }
-
- public double getManaCost() {
- return mana;
- }
-
- public double getCooldown() {
- return cooldown;
- }
-
- public boolean isSuccessful() {
- return cancelReason == null;
- }
-
- public CancelReason getCancelReason() {
- return cancelReason;
- }
-
- public void abort() {
- abort(CancelReason.OTHER);
- }
-
- public void abort(CancelReason reason) {
- cancelReason = reason;
- }
-
- public double getModifier(String modifier) {
- return skill.getModifier(modifier, level);
- }
-
- public enum CancelReason {
-
- // skill flag
- FLAG,
-
- // not enough mana
- MANA,
-
- // not enough stamina
- STAMINA,
-
- // skill still on cooldown
- COOLDOWN,
-
- // skill still not unlocked
- LOCKED,
-
- // no reason specified
- OTHER
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/api/skill/result/LocationSkillResult.java b/src/main/java/net/Indyuce/mmocore/api/skill/result/LocationSkillResult.java
deleted file mode 100644
index e13acc22..00000000
--- a/src/main/java/net/Indyuce/mmocore/api/skill/result/LocationSkillResult.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package net.Indyuce.mmocore.api.skill.result;
-
-import org.bukkit.FluidCollisionMode;
-import org.bukkit.Location;
-import org.bukkit.util.RayTraceResult;
-
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.MMOCoreUtils;
-
-public class LocationSkillResult extends SkillResult {
- private Location loc;
-
- /**
- * @param data Player casting the skill
- * @param skill Skill being cast
- * @param range Skill raycast range
- */
- public LocationSkillResult(PlayerData data, SkillInfo skill, double range) {
- this(data, skill, range, false);
- }
-
- /**
- * @param data Player casting the skill
- * @param skill Skill being cast
- * @param range Skill raycast range
- * @param buff If the skill is a buff ie if it can be cast on party members
- */
- public LocationSkillResult(PlayerData data, SkillInfo skill, double range, boolean buff) {
- super(data, skill);
-
- if (isSuccessful()) {
-
- RayTraceResult result = data.getPlayer().getWorld().rayTrace(data.getPlayer().getEyeLocation(),
- data.getPlayer().getEyeLocation().getDirection(), range, FluidCollisionMode.ALWAYS, true, 1.0D,
- entity -> MMOCoreUtils.canTarget(data, entity, buff));
- if (result == null)
- abort(CancelReason.OTHER);
- else
- loc = result.getHitBlock() != null ? result.getHitBlock().getLocation()
- : result.getHitEntity() != null ? result.getHitEntity().getLocation() : null;
- }
- }
-
- public boolean hasHit() {
- return loc != null;
- }
-
- public Location getHit() {
- return loc;
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/api/skill/result/TargetSkillResult.java b/src/main/java/net/Indyuce/mmocore/api/skill/result/TargetSkillResult.java
deleted file mode 100644
index c5e3d34d..00000000
--- a/src/main/java/net/Indyuce/mmocore/api/skill/result/TargetSkillResult.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package net.Indyuce.mmocore.api.skill.result;
-
-import org.bukkit.entity.LivingEntity;
-
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.MMOCoreUtils;
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.MMORayTraceResult;
-
-public class TargetSkillResult extends SkillResult {
- private LivingEntity target;
-
- /**
- * @param data Player casting the skill
- * @param skill Skill being cast
- * @param range Skill raycast range
- */
- public TargetSkillResult(PlayerData data, SkillInfo skill, double range) {
- this(data, skill, range, false);
- }
-
- /**
- * @param data Player casting the skill
- * @param skill Skill being cast
- * @param range Skill raycast range
- * @param buff If the skill is a buff ie if it can be cast on party members
- */
- public TargetSkillResult(PlayerData data, SkillInfo skill, double range, boolean buff) {
- super(data, skill);
-
- if (isSuccessful()) {
- MMORayTraceResult result = MythicLib.plugin.getVersion().getWrapper().rayTrace(data.getPlayer(), range,
- entity -> MMOCoreUtils.canTarget(data, entity, buff));
- if (!result.hasHit())
- abort();
- else
- target = result.getHit();
- }
- }
-
- // check skill result abort reason instead
- @Deprecated
- public boolean hasTarget() {
- return target != null;
- }
-
- public LivingEntity getTarget() {
- return target;
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/command/rpg/booster/ListCommandTreeNode.java b/src/main/java/net/Indyuce/mmocore/command/rpg/booster/ListCommandTreeNode.java
index 2c57f5df..73363fa9 100644
--- a/src/main/java/net/Indyuce/mmocore/command/rpg/booster/ListCommandTreeNode.java
+++ b/src/main/java/net/Indyuce/mmocore/command/rpg/booster/ListCommandTreeNode.java
@@ -21,7 +21,7 @@ public class ListCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
sender.sendMessage(ChatColor.YELLOW + "----------------------------------------------------");
- for (Booster booster : MMOCore.plugin.boosterManager.getBoosters())
+ for (Booster booster : MMOCore.plugin.boosterManager.getActive())
if (!booster.isTimedOut())
MythicLib.plugin.getVersion().getWrapper().sendJson((Player) sender, "{\"text\":\"" + ChatColor.YELLOW + "- " + ChatColor.GOLD
+ MythicLib.plugin.getMMOConfig().decimal.format((1 + booster.getExtra())) + "x" + ChatColor.YELLOW + " Booster - "
diff --git a/src/main/java/net/Indyuce/mmocore/command/rpg/booster/RemoveCommandTreeNode.java b/src/main/java/net/Indyuce/mmocore/command/rpg/booster/RemoveCommandTreeNode.java
index 9c07520a..c10cd4dd 100644
--- a/src/main/java/net/Indyuce/mmocore/command/rpg/booster/RemoveCommandTreeNode.java
+++ b/src/main/java/net/Indyuce/mmocore/command/rpg/booster/RemoveCommandTreeNode.java
@@ -16,7 +16,7 @@ public class RemoveCommandTreeNode extends CommandTreeNode {
super(parent, "remove");
addParameter(new Parameter("",
- (explorer, list) -> MMOCore.plugin.boosterManager.getBoosters().forEach(booster -> list.add("" + booster.getUniqueId().toString()))));
+ (explorer, list) -> MMOCore.plugin.boosterManager.getActive().forEach(booster -> list.add("" + booster.getUniqueId().toString()))));
}
@Override
@@ -32,7 +32,7 @@ public class RemoveCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
- for (Iterator iterator = MMOCore.plugin.boosterManager.getBoosters().iterator(); iterator.hasNext();) {
+ for (Iterator iterator = MMOCore.plugin.boosterManager.getActive().iterator(); iterator.hasNext();) {
Booster booster = iterator.next();
if (booster.getUniqueId().equals(uuid)) {
iterator.remove();
diff --git a/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/MythicMobsDrops.java b/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/MythicMobsDrops.java
index 30944d24..2a784ef7 100644
--- a/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/MythicMobsDrops.java
+++ b/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/MythicMobsDrops.java
@@ -1,8 +1,5 @@
package net.Indyuce.mmocore.comp.mythicmobs;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-
import io.lumine.xikage.mythicmobs.MythicMobs;
import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicDropLoadEvent;
import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicReloadedEvent;
@@ -10,40 +7,43 @@ import io.lumine.xikage.mythicmobs.skills.placeholders.Placeholder;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.comp.mythicmobs.load.CurrencyItemDrop;
import net.Indyuce.mmocore.comp.mythicmobs.load.GoldPouchDrop;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
public class MythicMobsDrops implements Listener {
- public MythicMobsDrops() {
- registerPlaceholders();
- }
+ public MythicMobsDrops() {
+ registerPlaceholders();
+ }
- @EventHandler
- public void a(MythicDropLoadEvent event) {
+ @EventHandler
+ public void a(MythicDropLoadEvent event) {
- // random gold pouches
- if (event.getDropName().equalsIgnoreCase("gold_pouch") || event.getDropName().equalsIgnoreCase("goldpouch"))
- event.register(new GoldPouchDrop(event.getConfig()));
+ // random gold pouches
+ if (event.getDropName().equalsIgnoreCase("gold_pouch") || event.getDropName().equalsIgnoreCase("goldpouch"))
+ event.register(new GoldPouchDrop(event.getConfig()));
- // gold coins
- if (event.getDropName().equalsIgnoreCase("gold_coin") || event.getDropName().equalsIgnoreCase("coin"))
- event.register(new CurrencyItemDrop("GOLD_COIN", event.getConfig()));
+ // gold coins
+ if (event.getDropName().equalsIgnoreCase("gold_coin") || event.getDropName().equalsIgnoreCase("coin"))
+ event.register(new CurrencyItemDrop("GOLD_COIN", event.getConfig()));
- // notes
- if (event.getDropName().equalsIgnoreCase("note") || event.getDropName().equalsIgnoreCase("banknote") || event.getDropName().equalsIgnoreCase("bank_note"))
- event.register(new CurrencyItemDrop("NOTE", event.getConfig()));
- }
+ // notes
+ if (event.getDropName().equalsIgnoreCase("note") || event.getDropName().equalsIgnoreCase("banknote") || event.getDropName().equalsIgnoreCase("bank_note"))
+ event.register(new CurrencyItemDrop("NOTE", event.getConfig()));
+ }
- /*
- * when MythicMobs is reloaded, the placeholders are emptied. Add them again
- */
- @EventHandler
- public void b(MythicReloadedEvent event) {
- registerPlaceholders();
- }
+ /*
+ * when MythicMobs is reloaded, the placeholders are emptied. Add them again
+ */
+ @EventHandler
+ public void b(MythicReloadedEvent event) {
+ registerPlaceholders();
+ }
- private void registerPlaceholders() {
- MythicMobs.inst().getPlaceholderManager().register("mmocore.skill", Placeholder.meta((metadata, arg) -> String.valueOf(PlayerData.get(metadata.getCaster().getEntity().getUniqueId()).getSkillData().getCachedModifier(arg))));
- MythicMobs.inst().getPlaceholderManager().register("mmocore.skill.int", Placeholder.meta((metadata, arg) -> String.valueOf((int) PlayerData.get(metadata.getCaster().getEntity().getUniqueId()).getSkillData().getCachedModifier(arg))));
- MythicMobs.inst().getPlaceholderManager().register("mmocore.mana", Placeholder.meta((metadata, arg) -> String.valueOf((int) PlayerData.get(metadata.getCaster().getEntity().getUniqueId()).getMana())));
- MythicMobs.inst().getPlaceholderManager().register("mmocore.stamina", Placeholder.meta((metadata, arg) -> String.valueOf((int) PlayerData.get(metadata.getCaster().getEntity().getUniqueId()).getStamina())));
- }
+ private void registerPlaceholders() {
+ // TODO
+ /*MythicMobs.inst().getPlaceholderManager().register("mmocore.skill", Placeholder.meta((metadata, arg) -> String.valueOf(PlayerData.get(metadata.getCaster().getEntity().getUniqueId()).getSkillData().getCachedModifier(arg))));
+ MythicMobs.inst().getPlaceholderManager().register("mmocore.skill.int", Placeholder.meta((metadata, arg) -> String.valueOf((int) PlayerData.get(metadata.getCaster().getEntity().getUniqueId()).getSkillData().getCachedModifier(arg))));*/
+ MythicMobs.inst().getPlaceholderManager().register("mmocore.mana", Placeholder.meta((metadata, arg) -> String.valueOf((int) PlayerData.get(metadata.getCaster().getEntity().getUniqueId()).getMana())));
+ MythicMobs.inst().getPlaceholderManager().register("mmocore.stamina", Placeholder.meta((metadata, arg) -> String.valueOf((int) PlayerData.get(metadata.getCaster().getEntity().getUniqueId()).getStamina())));
+ }
}
\ No newline at end of file
diff --git a/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/MythicMobSkill.java b/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/MythicMobSkill.java
index c93b6380..693851a8 100644
--- a/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/MythicMobSkill.java
+++ b/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/MythicMobSkill.java
@@ -2,112 +2,117 @@ package net.Indyuce.mmocore.comp.mythicmobs.skill;
import io.lumine.mythic.lib.api.util.EnumUtils;
import io.lumine.xikage.mythicmobs.MythicMobs;
+import io.lumine.xikage.mythicmobs.adapters.AbstractEntity;
+import io.lumine.xikage.mythicmobs.adapters.AbstractLocation;
+import io.lumine.xikage.mythicmobs.adapters.bukkit.BukkitAdapter;
+import io.lumine.xikage.mythicmobs.mobs.GenericCaster;
+import io.lumine.xikage.mythicmobs.skills.SkillCaster;
+import io.lumine.xikage.mythicmobs.skills.SkillTrigger;
import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.SkillResult.CancelReason;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.comp.anticheat.CheatType;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.entity.Entity;
-import java.util.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
import java.util.logging.Level;
public class MythicMobSkill extends Skill {
- private final io.lumine.xikage.mythicmobs.skills.Skill skill;
- private final Map antiCheat = new HashMap<>();
+ private final io.lumine.xikage.mythicmobs.skills.Skill skill;
+ private final Map antiCheat = new HashMap<>();
- //private final BiFunction cast;
+ public MythicMobSkill(String id, FileConfiguration config) {
+ super(id);
- public MythicMobSkill(String id, FileConfiguration config) {
- super(id);
+ String mmId = config.getString("mythicmobs-skill-id");
+ Validate.notNull(mmId, "Could not find MM skill ID");
- String mmId = config.getString("mythicmobs-skill-id");
- Validate.notNull(mmId, "Could not find MM skill ID");
+ Optional opt = MythicMobs.inst().getSkillManager().getSkill(mmId);
+ Validate.isTrue(opt.isPresent(), "Could not find MM skill " + mmId);
+ skill = opt.get();
- Optional opt = MythicMobs.inst().getSkillManager().getSkill(mmId);
- Validate.isTrue(opt.isPresent(), "Could not find MM skill " + mmId);
- skill = opt.get();
+ String format = config.getString("material");
+ Validate.notNull(format, "Could not load skill material");
+ setIcon(MMOCoreUtils.readIcon(format));
- String format = config.getString("material");
- Validate.notNull(format, "Could not load skill material");
- setIcon(MMOCoreUtils.readIcon(format));
+ setName(config.getString("name"));
+ setLore(config.getStringList("lore"));
- setName(config.getString("name"));
- setLore(config.getStringList("lore"));
+ for (String key : config.getKeys(false)) {
+ Object mod = config.get(key);
+ if (mod instanceof ConfigurationSection)
+ addModifier(key, readLinearValue((ConfigurationSection) mod));
+ }
- for (String key : config.getKeys(false)) {
- Object mod = config.get(key);
- if (mod instanceof ConfigurationSection)
- addModifier(key, readLinearValue((ConfigurationSection) mod));
- }
+ if (config.isConfigurationSection("disable-anti-cheat"))
+ for (String key : config.getKeys(false)) {
+ Optional cheatType = EnumUtils.getIfPresent(CheatType.class, key.toUpperCase());
+ if (cheatType.isPresent() && config.isInt("disable-anti-cheat." + key))
+ antiCheat.put(cheatType.get(), config.getInt("disable-anti-cheat." + key));
+ else
+ MMOCore.log(Level.WARNING, "Invalid Anti-Cheat configuration for '" + id + "'!");
+ }
- if (config.isConfigurationSection("disable-anti-cheat"))
- for (String key : config.getKeys(false)) {
- Optional cheatType = EnumUtils.getIfPresent(CheatType.class, key.toUpperCase());
- if (cheatType.isPresent() && config.isInt("disable-anti-cheat." + key))
- antiCheat.put(cheatType.get(), config.getInt("disable-anti-cheat." + key));
- else
- MMOCore.log(Level.WARNING, "Invalid Anti-Cheat configuration for '" + id + "'!");
- }
+ if (config.isString("passive-type")) {
+ Optional passiveType = EnumUtils.getIfPresent(PassiveSkillType.class, config.getString("passive-type").toUpperCase());
+ Validate.isTrue(passiveType.isPresent(), "Invalid passive skill type");
+ setPassive();
+ Bukkit.getPluginManager().registerEvents(passiveType.get().getHandler(this), MMOCore.plugin);
+ }
+ }
- if (config.isString("passive-type")) {
- Optional passiveType = EnumUtils.getIfPresent(PassiveSkillType.class, config.getString("passive-type").toUpperCase());
- Validate.isTrue(passiveType.isPresent(), "Invalid passive skill type");
- setPassive();
- Bukkit.getPluginManager().registerEvents(passiveType.get().getHandler(this), MMOCore.plugin);
- }
+ public Map getAntiCheat() {
+ return antiCheat;
+ }
- // cast = config.getBoolean("target") ? (data, info) -> new
- // TargetSkillResult(data, info, def(config.getDouble("range"), 50)) :
- // (data, info) -> new SkillResult(data, info);
- }
+ public String getInternalName() {
+ return skill.getInternalName();
+ }
- public Map getAntiCheat() {
- return antiCheat;
- }
+ public io.lumine.xikage.mythicmobs.skills.Skill getSkill() {
+ return skill;
+ }
- public String getInternalName() {
- return skill.getInternalName();
- }
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ SkillMetadata cast = new SkillMetadata(caster, skill);
+ if (!cast.isSuccessful() || isPassive())
+ return cast;
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- SkillResult cast = new SkillResult(data, skill);
- if (!cast.isSuccessful() || !data.isOnline() || isPassive())
- return cast;
+ HashSet targetEntities = new HashSet<>();
+ HashSet targetLocations = new HashSet<>();
- List targets = new ArrayList<>();
- // targets.add(cast instanceof TargetSkillResult ? ((TargetSkillResult)
- // cast).getTarget() : stats.getPlayer());
- targets.add(data.getPlayer());
+ AbstractEntity trigger = BukkitAdapter.adapt(caster.getPlayer());
+ SkillCaster skillCaster = new GenericCaster(trigger);
+ io.lumine.xikage.mythicmobs.skills.SkillMetadata skillMeta = new io.lumine.xikage.mythicmobs.skills.SkillMetadata(SkillTrigger.API, skillCaster, trigger, BukkitAdapter.adapt(caster.getPlayer().getEyeLocation()), targetEntities, targetLocations, 1);
- /*
- * cache placeholders so they can be retrieved later by MythicMobs math
- * formulas
- */
- data.getSkillData().cacheModifiers(this, cast);
- if (MMOCore.plugin.hasAntiCheat())
- MMOCore.plugin.antiCheatSupport.disableAntiCheat(data.getPlayer(), antiCheat);
- if (!MythicMobs.inst().getAPIHelper().castSkill(data.getPlayer(), this.skill.getInternalName(), data.getPlayer(),
- data.getPlayer().getEyeLocation(), targets, null, 1))
- cast.abort(CancelReason.OTHER);
+ // Disable anticheat
+ if (MMOCore.plugin.hasAntiCheat())
+ MMOCore.plugin.antiCheatSupport.disableAntiCheat(caster.getPlayer(), antiCheat);
- return cast;
- }
+ if (this.skill.usable(skillMeta, SkillTrigger.API))
+ this.skill.execute(skillMeta);
+ else
+ cast.abort();
- /**
- * Used to load double modifiers from the config with a specific type, since
- * modifiers have initially a type for mmocore default skills
- */
- private LinearValue readLinearValue(ConfigurationSection section) {
- return section.getBoolean("int") ? new IntegerLinearValue(section) : new LinearValue(section);
- }
+ return cast;
+ }
+
+ /**
+ * Used to load double modifiers from the config with a specific type, since
+ * modifiers have initially a type for mmocore default skills
+ */
+ private LinearValue readLinearValue(ConfigurationSection section) {
+ return section.getBoolean("int") ? new IntegerLinearValue(section) : new LinearValue(section);
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/PassiveMythicMobSkillHandler.java b/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/PassiveMythicMobSkillHandler.java
index 5de8046b..121835fd 100644
--- a/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/PassiveMythicMobSkillHandler.java
+++ b/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/PassiveMythicMobSkillHandler.java
@@ -1,40 +1,65 @@
package net.Indyuce.mmocore.comp.mythicmobs.skill;
-import io.lumine.xikage.mythicmobs.MythicMobs;
+import io.lumine.xikage.mythicmobs.adapters.AbstractEntity;
+import io.lumine.xikage.mythicmobs.adapters.AbstractLocation;
+import io.lumine.xikage.mythicmobs.adapters.bukkit.BukkitAdapter;
+import io.lumine.xikage.mythicmobs.mobs.GenericCaster;
+import io.lumine.xikage.mythicmobs.skills.SkillCaster;
+import io.lumine.xikage.mythicmobs.skills.SkillTrigger;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.SkillResult;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
import org.bukkit.entity.Entity;
import org.bukkit.event.Listener;
-import java.util.Collections;
+import java.util.HashSet;
public abstract class PassiveMythicMobSkillHandler implements Listener {
- protected final MythicMobSkill skill;
-
- /**
- * Core class for all passive types
- */
- protected PassiveMythicMobSkillHandler(MythicMobSkill skill) {
- this.skill = skill;
- }
-
- public void castSkill(PlayerData data) {
- castSkill(data, data.getPlayer());
- }
+ protected final MythicMobSkill skill;
- public void castSkill(PlayerData data, Entity target) {
- if (!data.getProfess().hasSkill(skill.getId()))
- return;
+ /**
+ * Core class for all passive types
+ */
+ protected PassiveMythicMobSkillHandler(MythicMobSkill skill) {
+ this.skill = skill;
+ }
- SkillResult cast = data.cast(data.getProfess().getSkill(skill.getId()));
- if (!cast.isSuccessful())
- return;
+ public SkillMetadata castSkill(PlayerData data) {
+ return castSkill(data, null);
+ }
- data.getSkillData().cacheModifiers(skill.getInternalName(), cast);
- if (MMOCore.plugin.hasAntiCheat())
- MMOCore.plugin.antiCheatSupport.disableAntiCheat(data.getPlayer(), skill.getAntiCheat());
- MythicMobs.inst().getAPIHelper().castSkill(data.getPlayer(), skill.getInternalName(), target,
- data.getPlayer().getEyeLocation(), Collections.singletonList(data.getPlayer()), null, 1);
- }
+ public SkillMetadata castSkill(PlayerData playerData, Entity target) {
+ if (!playerData.getProfess().hasSkill(skill))
+ return null;
+
+ Skill.SkillInfo skill = playerData.getProfess().getSkill(this.skill);
+ CasterMetadata caster = new CasterMetadata(playerData);
+ SkillMetadata cast = new SkillMetadata(caster, skill);
+ if (!cast.isSuccessful() || this.skill.isPassive())
+ return cast;
+
+ HashSet targetEntities = new HashSet<>();
+ HashSet targetLocations = new HashSet<>();
+
+ // The only difference
+ if (target != null)
+ targetEntities.add(BukkitAdapter.adapt(target));
+
+ AbstractEntity trigger = BukkitAdapter.adapt(caster.getPlayer());
+ SkillCaster skillCaster = new GenericCaster(trigger);
+ io.lumine.xikage.mythicmobs.skills.SkillMetadata skillMeta = new io.lumine.xikage.mythicmobs.skills.SkillMetadata(SkillTrigger.API, skillCaster, trigger, BukkitAdapter.adapt(caster.getPlayer().getEyeLocation()), targetEntities, targetLocations, 1);
+
+ // Disable anticheat
+ if (MMOCore.plugin.hasAntiCheat())
+ MMOCore.plugin.antiCheatSupport.disableAntiCheat(caster.getPlayer(), this.skill.getAntiCheat());
+
+ if (this.skill.getSkill().usable(skillMeta, SkillTrigger.API))
+ this.skill.getSkill().execute(skillMeta);
+ else
+ cast.abort();
+
+ return cast;
+ }
}
diff --git a/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/handlers/PlayerDamageSkillHandler.java b/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/handlers/PlayerDamageSkillHandler.java
index 8f818ab4..7658185e 100644
--- a/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/handlers/PlayerDamageSkillHandler.java
+++ b/src/main/java/net/Indyuce/mmocore/comp/mythicmobs/skill/handlers/PlayerDamageSkillHandler.java
@@ -18,8 +18,8 @@ public class PlayerDamageSkillHandler extends PassiveMythicMobSkillHandler {
}
@EventHandler
- private void event(EntityDamageEvent e) {
- if (e.getEntityType() == EntityType.PLAYER && !e.getEntity().hasMetadata("NPC"))
- castSkill(PlayerData.get((Player) e.getEntity()));
+ private void event(EntityDamageEvent event) {
+ if (event.getEntityType() == EntityType.PLAYER && !event.getEntity().hasMetadata("NPC"))
+ castSkill(PlayerData.get((Player) event.getEntity()));
}
}
diff --git a/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java b/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java
index 60c2a345..6bac95e8 100644
--- a/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java
+++ b/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java
@@ -10,7 +10,6 @@ import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.util.math.format.DelayFormat;
import net.Indyuce.mmocore.gui.api.EditableInventory;
import net.Indyuce.mmocore.gui.api.GeneratedInventory;
-import net.Indyuce.mmocore.gui.api.PluginInventory;
import net.Indyuce.mmocore.gui.api.item.InventoryItem;
import net.Indyuce.mmocore.gui.api.item.Placeholders;
import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem;
@@ -43,7 +42,7 @@ public class PlayerStats extends EditableInventory {
@Override
public boolean canDisplay(PlayerStatsInventory inv) {
InventoryItem boost = inv.getByFunction("boost");
- return boost != null && inv.boostOffset + boost.getSlots().size() < MMOCore.plugin.boosterManager.getBoosters().size();
+ return boost != null && inv.boostOffset + boost.getSlots().size() < MMOCore.plugin.boosterManager.getActive().size();
}
};
@@ -304,7 +303,7 @@ public class PlayerStats extends EditableInventory {
@Override
public ItemStack display(PlayerStatsInventory inv, int n) {
int offset = inv.boostOffset;
- if (n + offset >= MMOCore.plugin.boosterManager.getBoosters().size())
+ if (n + offset >= MMOCore.plugin.boosterManager.getActive().size())
return noBoost.display(inv, n);
Booster boost = MMOCore.plugin.boosterManager.get(inv.boostOffset + n);
diff --git a/src/main/java/net/Indyuce/mmocore/gui/SkillList.java b/src/main/java/net/Indyuce/mmocore/gui/SkillList.java
index a1beb56e..e5e2ba01 100644
--- a/src/main/java/net/Indyuce/mmocore/gui/SkillList.java
+++ b/src/main/java/net/Indyuce/mmocore/gui/SkillList.java
@@ -5,8 +5,8 @@ import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.gui.api.EditableInventory;
import net.Indyuce.mmocore.gui.api.GeneratedInventory;
diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java b/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java
index 4fe60788..b3cca611 100644
--- a/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java
+++ b/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java
@@ -1,16 +1,15 @@
package net.Indyuce.mmocore.gui.api;
-import java.util.ArrayList;
-import java.util.List;
-
+import io.lumine.mythic.lib.MythicLib;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.gui.api.item.InventoryItem;
+import net.Indyuce.mmocore.gui.api.item.TriggerItem;
import org.bukkit.Bukkit;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.gui.api.item.InventoryItem;
-import net.Indyuce.mmocore.gui.api.item.TriggerItem;
-import io.lumine.mythic.lib.MythicLib;
+import java.util.ArrayList;
+import java.util.List;
public abstract class GeneratedInventory extends PluginInventory {
private final EditableInventory editable;
@@ -44,9 +43,10 @@ public abstract class GeneratedInventory extends PluginInventory {
return null;
}
- /*
- * this method must use an ordered collection because of GUI items
- * overriding possibilities.
+ /**
+ * This method must use an ordered collection because
+ * of GUI items overriding possibilities. Hence the use
+ * of an array list instead of a set
*/
public void addLoaded(InventoryItem item) {
loaded.add(0, item);
@@ -66,7 +66,7 @@ public abstract class GeneratedInventory extends PluginInventory {
public void open() {
/*
- * very important, in order to prevent ghost items, the loaded items map
+ * Very important, in order to prevent ghost items, the loaded items map
* must be cleared when the inventory is updated or open at least twice
*/
loaded.clear();
diff --git a/src/main/java/net/Indyuce/mmocore/listener/SpellCast.java b/src/main/java/net/Indyuce/mmocore/listener/SpellCast.java
index 537ae3cc..06580e32 100644
--- a/src/main/java/net/Indyuce/mmocore/listener/SpellCast.java
+++ b/src/main/java/net/Indyuce/mmocore/listener/SpellCast.java
@@ -13,7 +13,7 @@ import org.bukkit.scheduler.BukkitRunnable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
import net.Indyuce.mmocore.manager.ConfigManager;
import net.Indyuce.mmocore.manager.SoundManager;
diff --git a/src/main/java/net/Indyuce/mmocore/listener/option/PlayerProfileCheck.java b/src/main/java/net/Indyuce/mmocore/listener/option/PlayerProfileCheck.java
new file mode 100644
index 00000000..c0080fc7
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/listener/option/PlayerProfileCheck.java
@@ -0,0 +1,29 @@
+package net.Indyuce.mmocore.listener.option;
+
+import io.lumine.mythic.lib.MythicLib;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.manager.InventoryManager;
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+import org.bukkit.inventory.Inventory;
+
+public class PlayerProfileCheck implements Listener {
+
+ @EventHandler
+ public void a(PlayerInteractEntityEvent event) {
+ if (event.getRightClicked().getType() != EntityType.PLAYER || MythicLib.plugin.getEntities().findCustom(event.getRightClicked()))
+ return;
+
+ /*
+ * This works because the PlayerStats class DOES NOT utilize
+ * at all the player instance saved in the InventoryClickEvent
+ *
+ * Opening inventories like that to other players does NOT
+ * necessarily works for any other custom inventory.
+ * */
+ Inventory inv = InventoryManager.PLAYER_STATS.newInventory(PlayerData.get(event.getRightClicked().getUniqueId())).getInventory();
+ event.getPlayer().openInventory(inv);
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/manager/SkillManager.java b/src/main/java/net/Indyuce/mmocore/manager/SkillManager.java
index ae5444e0..edbebb22 100644
--- a/src/main/java/net/Indyuce/mmocore/manager/SkillManager.java
+++ b/src/main/java/net/Indyuce/mmocore/manager/SkillManager.java
@@ -17,7 +17,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigFile;
-import net.Indyuce.mmocore.api.skill.Skill;
+import net.Indyuce.mmocore.skill.Skill;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.comp.mythicmobs.skill.MythicMobSkill;
@@ -36,7 +36,7 @@ public class SkillManager {
JarFile jarFile = new JarFile(MMOCore.plugin.getJarFile());
JarEntry entry;
for (Enumeration en = jarFile.entries(); en.hasMoreElements();)
- if ((entry = en.nextElement()).getName().startsWith("net/Indyuce/mmocore/skill/")
+ if ((entry = en.nextElement()).getName().startsWith("net/Indyuce/mmocore/skill/list/")
&& !entry.isDirectory() && !entry.getName().contains("$"))
register((Skill) Class.forName(entry.getName().replace("/", ".").replace(".class", ""))
.newInstance());
diff --git a/src/main/java/net/Indyuce/mmocore/manager/social/BoosterManager.java b/src/main/java/net/Indyuce/mmocore/manager/social/BoosterManager.java
index c9590faf..d689c014 100644
--- a/src/main/java/net/Indyuce/mmocore/manager/social/BoosterManager.java
+++ b/src/main/java/net/Indyuce/mmocore/manager/social/BoosterManager.java
@@ -41,7 +41,7 @@ public class BoosterManager {
/**
* Cleans timed out boosters from the MMOCore registry
*/
- public void flush() {
+ private void flush() {
map.removeIf(Booster::isTimedOut);
}
@@ -66,14 +66,7 @@ public class BoosterManager {
* @return Collection of currently registered boosters. Some of them can be
* expired but are not unregistered yet!
*/
- public List getBoosters() {
- return map;
- }
-
- /**
- * @return Same as {@link #getBoosters()} but does not include timed out boosters
- */
- public List getActiveBoosters() {
+ public List getActive() {
return map.stream().filter((b) -> !b.isTimedOut()).collect(Collectors.toList());
}
}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Ambers.java b/src/main/java/net/Indyuce/mmocore/skill/Ambers.java
deleted file mode 100644
index a6338a21..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Ambers.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.player.stats.StatType;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
-import org.bukkit.*;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.scheduler.BukkitRunnable;
-
-public class Ambers extends Skill implements Listener {
- public Ambers() {
- super();
- setMaterial(Material.EMERALD);
- setLore("Dealing magic damage has &630% &7chance", "of dropping an amber on the ground.", "", "When picked up, ambers stack and",
- "refund &9{percent}% &7of your missing mana.", "", "&oAmbers can be used in other damaging skills.",
- "&oThe more you collect, the more powerful the skills.", "", "&e{cooldown}s Cooldown");
- setPassive();
-
- addModifier("cooldown", new LinearValue(3, -.1, 1, 3));
- addModifier("percent", new LinearValue(10, .1, 10, 20));
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- @EventHandler
- public void a(PlayerAttackEvent event) {
- PlayerData data = PlayerData.get(event.getData().getUniqueId());
- if (!event.getAttack().hasType(DamageType.SKILL) || !data.getProfess().hasSkill(this))
- return;
-
- SkillResult cast = data.cast(this);
- if (!cast.isSuccessful())
- return;
-
- Location loc = event.getEntity().getLocation();
- double a = random.nextDouble() * 2 * Math.PI;
-
- new Amber(data, loc.add(0, event.getEntity().getHeight() / 2, 0), loc.clone().add(4 * Math.cos(a), 0, 4 * Math.sin(a)), cast.getModifier("percent"));
- }
-
- public static class Amber extends BukkitRunnable {
- private final Location loc;
- private final PlayerData data;
- private final double percent;
-
- private int j;
-
- private Amber(PlayerData data, Location source, Location loc, double percent) {
- this.loc = loc;
- this.data = data;
- this.percent = percent / 100;
-
- final Amber amber = this;
- new ParabolicProjectile(source, loc, Particle.REDSTONE, () -> amber.runTaskTimer(MMOCore.plugin, 0, 3), 1, Color.ORANGE, 1.3f);
- }
-
- @Override
- public void run() {
- if(!data.isOnline()) return;
- if (j++ > 66 || !data.getPlayer().getWorld().equals(loc.getWorld())) {
- cancel();
- return;
- }
-
- if (data.getPlayer().getLocation().distanceSquared(loc) < 2) {
-
- data.getPlayer().playSound(data.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 1);
- // data.getSkillData().ambers++;
- data.giveMana((data.getStats().getStat(StatType.MAX_MANA) - data.getMana()) * percent, PlayerResourceUpdateEvent.UpdateReason.SKILL_REGENERATION);
-
- cancel();
- return;
- }
-
- for (int j = 0; j < 5; j++)
- loc.getWorld().spawnParticle(Particle.SPELL_MOB, loc, 0, 1, 0.647, 0, 1);
- loc.getWorld().spawnParticle(Particle.REDSTONE, loc, 1, new Particle.DustOptions(Color.ORANGE, 1.3f));
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Backstab.java b/src/main/java/net/Indyuce/mmocore/skill/Backstab.java
deleted file mode 100644
index 7fcc8b4e..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Backstab.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
-
-public class Backstab extends Skill implements Listener {
- public Backstab() {
- super();
- setMaterial(Material.FLINT);
- setLore("Backstabs deal &c{extra}%&7 damage.", "", "&9Costs {mana} {mana_name}");
- setPassive();
-
- addModifier("cooldown", new LinearValue(0, 0));
- addModifier("mana", new LinearValue(8, 1));
- addModifier("extra", new LinearValue(50, 20));
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- @EventHandler
- public void a(PlayerAttackEvent event) {
- PlayerData data = PlayerData.get(event.getData().getUniqueId());
- LivingEntity target = event.getEntity();
- if (data.isInCombat() || !event.getAttack().hasType(DamageType.WEAPON)
- || event.getPlayer().getEyeLocation().getDirection().angle(target.getEyeLocation().getDirection()) > Math.PI / 6
- || !data.getProfess().hasSkill(this))
- return;
-
- SkillResult cast = data.cast(this);
- if (!cast.isSuccessful())
- return;
-
- data.cast(cast.getInfo());
- event.getAttack().multiplyDamage(1 + cast.getModifier("extra") / 100);
- target.getWorld().spawnParticle(Particle.CRIT, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, .05);
- target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ENDERMAN_HURT, 1, 1.5f);
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/CasterMetadata.java b/src/main/java/net/Indyuce/mmocore/skill/CasterMetadata.java
new file mode 100644
index 00000000..573a092b
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/CasterMetadata.java
@@ -0,0 +1,57 @@
+package net.Indyuce.mmocore.skill;
+
+import io.lumine.mythic.lib.MythicLib;
+import io.lumine.mythic.lib.api.player.EquipmentSlot;
+import io.lumine.mythic.lib.api.stat.StatMap;
+import io.lumine.mythic.lib.damage.AttackMetadata;
+import io.lumine.mythic.lib.damage.DamageMetadata;
+import io.lumine.mythic.lib.damage.DamageType;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+
+public class CasterMetadata {
+ private final Player player;
+ private final PlayerData caster;
+ private final StatMap.CachedStatMap stats;
+
+ /**
+ * Instantiated every time a player casts a skill. This is
+ * used to temporarily cache the player's statistics
+ *
+ * @param caster Player casting the skill
+ */
+ public CasterMetadata(PlayerData caster) {
+ this.player = caster.getPlayer();
+ this.caster = caster;
+ this.stats = caster.getMMOPlayerData().getStatMap().cache(EquipmentSlot.MAIN_HAND);
+ }
+
+ public Player getPlayer() {
+ return player;
+ }
+
+ public PlayerData getPlayerData() {
+ return caster;
+ }
+
+ public StatMap.CachedStatMap getStats() {
+ return stats;
+ }
+
+ /**
+ * Utility method that makes a player deal damage to a specific
+ * entity. This creates the attackMetadata based on the data
+ * stored by the CasterMetadata, and calls it using MythicLib
+ * damage manager
+ *
+ * @param target Target entity
+ * @param damage Damage dealt
+ * @param types Type of target
+ * @return
+ */
+ public void attack(LivingEntity target, double damage, DamageType... types) {
+ AttackMetadata attackMeta = new AttackMetadata(new DamageMetadata(damage, types), stats);
+ MythicLib.plugin.getDamage().damage(attackMeta, target);
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Combo_Attack.java b/src/main/java/net/Indyuce/mmocore/skill/Combo_Attack.java
deleted file mode 100644
index 661543be..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Combo_Attack.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.scheduler.BukkitRunnable;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
-
-public class Combo_Attack extends Skill {
- public Combo_Attack() {
- super();
- setMaterial(Material.IRON_SWORD);
- setLore("Violenty slashes your target &8{count}", "times for a total of &8{damage} &7damage.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(20, -.1, 5, 20));
- addModifier("damage", new LinearValue(9, .3));
- addModifier("count", new LinearValue(3, .2));
- addModifier("mana", new LinearValue(10, -.1, 3, 5));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- TargetSkillResult cast = new TargetSkillResult(data, skill, 3);
- if (!cast.isSuccessful())
- return cast;
-
- new BukkitRunnable() {
- final int count = (int) cast.getModifier("count");
- final double damage = cast.getModifier("damage") / count;
- final LivingEntity target = cast.getTarget();
-
- int c;
-
- @Override
- public void run() {
- if(!data.isOnline()) return;
- if (c++ > count) {
- cancel();
- return;
- }
-
- target.getWorld().playSound(target.getLocation(), Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, 1, 2);
- target.getWorld().spawnParticle(Particle.CRIT, target.getLocation().add(0, target.getHeight() / 2, 0), 24, 0, 0, 0, .7);
- MythicLib.plugin.getDamage().damage(data.getPlayer(), target, new AttackResult(damage, DamageType.SKILL, DamageType.PHYSICAL));
- }
- }.runTaskTimer(MMOCore.plugin, 0, 5);
- return cast;
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Control.java b/src/main/java/net/Indyuce/mmocore/skill/Control.java
deleted file mode 100644
index 6887d08f..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Control.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerInteractEvent;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
-import org.bukkit.scheduler.BukkitRunnable;
-import org.bukkit.util.Vector;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.version.VersionMaterial;
-import io.lumine.mythic.lib.version.VersionSound;
-
-public class Control extends Skill {
- public Control() {
- super();
- setMaterial(VersionMaterial.MAGENTA_DYE.toMaterial());
- setLore("Your target is temporarily slowed for &8{duration} &7seconds.", "As soon as you left click, it gets", "pushed back where you are looking at.", "Knockback force: &f{knockback}%", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(18, -.3, 10, 20));
- addModifier("mana", new LinearValue(15, 1.5));
- addModifier("knockback", new LinearValue(30, 3));
- addModifier("duration", new LinearValue(2, 0));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- TargetSkillResult cast = new TargetSkillResult(data, skill, 7);
- if (!cast.isSuccessful())
- return cast;
-
- if(data.isOnline())
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 1);
- cast.getTarget().addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 0));
- new TelekinesyRunnable(data, cast.getTarget(), cast.getModifier("knockback") / 100, cast.getModifier("duration"));
- return cast;
- }
-
- public static class TelekinesyRunnable extends BukkitRunnable implements Listener {
- private final LivingEntity entity;
- private final PlayerData data;
-
- private final double f, d;
-
- private int j;
-
- public TelekinesyRunnable(PlayerData data, LivingEntity entity, double force, double duration) {
- this.entity = entity;
- this.data = data;
-
- d = duration * 20;
- f = force;
-
- runTaskTimer(MMOCore.plugin, 0, 1);
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- @EventHandler
- public void a(PlayerInteractEvent event) {
- if(!data.isOnline()) return;
- if (event.getPlayer().equals(data.getPlayer()) && event.getAction().name().contains("LEFT_CLICK")) {
- Vector vec = data.getPlayer().getEyeLocation().getDirection().multiply(3 * f);
- vec.setY(Math.max(.5, vec.getY() / 2));
- entity.setVelocity(vec);
-
- /*
- * try not to interfere with other potion effects
- */
- PotionEffect effect = entity.getPotionEffect(PotionEffectType.SLOW);
- if (effect.getDuration() < d && effect.getAmplifier() == 0)
- entity.removePotionEffect(PotionEffectType.SLOW);
-
- entity.getWorld().spawnParticle(Particle.SPELL_WITCH, entity.getLocation().add(0, entity.getHeight() / 2, 0), 16);
- entity.getWorld().playSound(entity.getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, 1);
- close();
- }
- }
-
- @Override
- public void run() {
- if (!data.isOnline() || entity.isDead() || j++ >= d) {
- close();
- return;
- }
-
- double a = (double) j / 3;
- entity.getWorld().spawnParticle(Particle.SPELL_WITCH, entity.getLocation().add(Math.cos(a), entity.getHeight() / 2, Math.sin(a)), 0);
- }
-
- private void close() {
- cancel();
- HandlerList.unregisterAll(this);
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Deep_Wound.java b/src/main/java/net/Indyuce/mmocore/skill/Deep_Wound.java
deleted file mode 100644
index 0f338aaf..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Deep_Wound.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.attribute.Attribute;
-import org.bukkit.entity.LivingEntity;
-
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
-
-public class Deep_Wound extends Skill {
- public Deep_Wound() {
- super();
- setMaterial(Material.REDSTONE);
- setLore("You puncture your target, dealing &c{damage} &7damage.", "Damage is increased up to &c+{extra}% &7based",
- "on your target's missing health.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(20, -.1, 5, 20));
- addModifier("mana", new LinearValue(8, 3));
- addModifier("damage", new LinearValue(5, 1.5));
- addModifier("extra", new LinearValue(50, 20));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- TargetSkillResult cast = new TargetSkillResult(data, skill, 3);
- if (!cast.isSuccessful() || !data.isOnline())
- return cast;
-
- LivingEntity target = cast.getTarget();
- target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 2, 2);
- target.getWorld().spawnParticle(Particle.CRIT, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, .7);
- target.getWorld().spawnParticle(Particle.BLOCK_CRACK, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, 2,
- Material.REDSTONE_BLOCK.createBlockData());
-
- double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
- double ratio = (max - target.getHealth()) / max;
-
- double damage = cast.getModifier("damage") * (1 + cast.getModifier("extra") * ratio / 100);
- MythicLib.plugin.getDamage().damage(data.getPlayer(), target, new AttackResult(damage, DamageType.SKILL, DamageType.PHYSICAL));
- return cast;
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Empowered_Attack.java b/src/main/java/net/Indyuce/mmocore/skill/Empowered_Attack.java
deleted file mode 100644
index 2c99a5e8..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Empowered_Attack.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
-import io.lumine.mythic.lib.version.VersionMaterial;
-import io.lumine.mythic.lib.version.VersionSound;
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.MMOCoreUtils;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
-import org.bukkit.Bukkit;
-import org.bukkit.Location;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.util.Vector;
-
-public class Empowered_Attack extends Skill {
- private static final double perb = 5;
-
- public Empowered_Attack() {
- super();
- setMaterial(VersionMaterial.BONE_MEAL.toMaterial());
- setLore("You charge your weapon with lightning.", "Your next attack deals &f{extra}% &7extra damage", "and spreads to enemies within &f{radius} &7blocks", "for &f{ratio}% &7of the initial damage.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(10, -.2, 5, 10));
- addModifier("mana", new LinearValue(4, 1));
- addModifier("radius", new LinearValue(4, 0));
- addModifier("ratio", new LinearValue(30, 10, 30, 100));
- addModifier("extra", new LinearValue(30, 8));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- SkillResult cast = new SkillResult(data, skill);
- if (!cast.isSuccessful())
- return cast;
-
- if(data.isOnline())
- data.getPlayer().playSound(data.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 1);
- new EmpoweredAttack(data, cast.getModifier("extra"), cast.getModifier("ratio"), cast.getModifier("radius"));
- return cast;
- }
-
- private void drawVector(Location loc, Vector vec) {
-
- double steps = vec.length() * perb;
- Vector v = vec.clone().normalize().multiply((double) 1 / perb);
-
- for (int j = 0; j < Math.min(steps, 124); j++)
- loc.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc.add(v), 0);
- }
-
- public class EmpoweredAttack implements Listener {
- private final PlayerData player;
- private final double c, r, rad;
-
- public EmpoweredAttack(PlayerData player, double extra, double ratio, double radius) {
- this.player = player;
- this.c = 1 + extra / 100;
- this.r = ratio / 100;
- this.rad = radius;
-
- if(player.isOnline())
- new SmallParticleEffect(player.getPlayer(), Particle.FIREWORKS_SPARK);
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- Bukkit.getScheduler().scheduleSyncDelayedTask(MMOCore.plugin, this::close, 80);
- }
-
- private void close() {
- PlayerAttackEvent.getHandlerList().unregister(this);
- }
-
- @EventHandler
- public void a(PlayerAttackEvent event) {
- if(!player.isOnline()) return;
- if (event.getPlayer().equals(player.getPlayer()) && event.getAttack().hasType(DamageType.WEAPON)) {
- close();
-
- Entity target = event.getEntity();
-
- /*
- * play lightning effect
- */
- final Location loc = target.getLocation().add(0, target.getHeight() / 2, 0);
- for (int j = 0; j < 3; j++) {
- Location clone = loc.clone();
- double a = random.nextDouble() * Math.PI * 2;
- loc.add(Math.cos(a), 5, Math.sin(a));
- drawVector(clone, loc.clone().subtract(clone).toVector());
- }
-
- target.getWorld().playSound(target.getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, .5f);
- target.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, .2);
-
- double sweep = event.getAttack().getDamage() * r;
- Location src = target.getLocation().add(0, target.getHeight() / 2, 0);
-
- for (Entity entity : target.getNearbyEntities(rad, rad, rad))
- if (MMOCoreUtils.canTarget(player, entity)) {
- drawVector(src, entity.getLocation().add(0, entity.getHeight() / 2, 0).subtract(src).toVector());
- MythicLib.plugin.getDamage().damage(player.getPlayer(), (LivingEntity) entity, new AttackResult(sweep, DamageType.SKILL, DamageType.PHYSICAL));
- }
-
- /*
- * apply damage afterwards otherwise the damage dealt to nearby
- * entities scale with the extra ability damage.
- */
- event.getAttack().multiplyDamage(1 + c);
- }
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Evade.java b/src/main/java/net/Indyuce/mmocore/skill/Evade.java
deleted file mode 100644
index ae88973a..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Evade.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.entity.EntityDamageEvent;
-import org.bukkit.scheduler.BukkitRunnable;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
-import io.lumine.mythic.lib.version.VersionSound;
-
-public class Evade extends Skill {
- public Evade() {
- super();
- setMaterial(Material.LEATHER_BOOTS);
- setLore("You become imune to damage for &8{duration} &7seconds.", "Cancels when dealing weapon damage.", "", "&e{cooldown}s Cooldown",
- "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(20, 0));
- addModifier("mana", new LinearValue(8, 3));
- addModifier("duration", new LinearValue(2, .3, 2, 10));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- SkillResult cast = new SkillResult(data, skill);
- if (!cast.isSuccessful())
- return cast;
- if(data.isOnline()) {
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), VersionSound.ENTITY_ENDERMAN_TELEPORT.toSound(), 1, 2);
- new SmallParticleEffect(data.getPlayer(), Particle.CLOUD);
- }
- new EvadeSkill(data, cast.getModifier("duration"));
- return cast;
- }
-
- private static class EvadeSkill extends BukkitRunnable implements Listener {
- private final PlayerData data;
-
- public EvadeSkill(PlayerData data, double duration) {
- this.data = data;
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- runTaskTimer(MMOCore.plugin, 0, 1);
- Bukkit.getScheduler().runTaskLater(MMOCore.plugin, this::close, (long) (duration * 20));
- }
-
- private void close() {
- cancel();
- EntityDamageEvent.getHandlerList().unregister(this);
- }
-
- @EventHandler(priority = EventPriority.LOW)
- public void a(EntityDamageEvent event) {
- if(!data.isOnline()) return;
- if (event.getEntity().equals(data.getPlayer()))
- event.setCancelled(true);
- }
-
- @EventHandler(priority = EventPriority.HIGHEST)
- public void b(PlayerAttackEvent event) {
- if (event.getAttack().hasType(DamageType.WEAPON) && !event.isCancelled() && PlayerData.get(event.getData().getUniqueId()).equals(data))
- close();
- }
-
- @Override
- public void run() {
- if (!data.isOnline() || data.getPlayer().isDead())
- close();
- else
- data.getPlayer().getWorld().spawnParticle(Particle.CLOUD, data.getPlayer().getLocation().add(0, 1, 0), 0);
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Fire_Berserker.java b/src/main/java/net/Indyuce/mmocore/skill/Fire_Berserker.java
deleted file mode 100644
index fa7f81b5..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Fire_Berserker.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import java.util.Optional;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
-
-public class Fire_Berserker extends Skill implements Listener {
- public Fire_Berserker() {
- super();
- setMaterial(Material.FLINT_AND_STEEL);
- setLore("You deal &c{extra}% &7more damage when on fire.");
- setPassive();
-
- addModifier("extra", new LinearValue(10, 5));
- // addModifier("duration", new LinearValue(10, .1));
- // addModifier("cooldown", new LinearValue(30, 0));
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
- public void a(PlayerAttackEvent event) {
- PlayerData data = PlayerData.get(event.getData().getUniqueId());
- if (event.getPlayer().getFireTicks() > 0) {
- Optional skill = data.getProfess().findSkill(this);
- skill.ifPresent(skillInfo -> event.getAttack().multiplyDamage(1 + skillInfo.getModifier("extra", data.getSkillLevel(this)) / 100));
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Fire_Rage.java b/src/main/java/net/Indyuce/mmocore/skill/Fire_Rage.java
deleted file mode 100644
index 53a12a29..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Fire_Rage.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Location;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerInteractEvent;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
-import org.bukkit.scheduler.BukkitRunnable;
-import org.bukkit.util.Vector;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.MMOCoreUtils;
-import net.Indyuce.mmocore.api.util.math.VectorRotation;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.version.VersionMaterial;
-import io.lumine.mythic.lib.version.VersionSound;
-
-public class Fire_Rage extends Skill {
- public Fire_Rage() {
- super();
- setMaterial(VersionMaterial.FIRE_CHARGE.toMaterial());
- setLore("For {duration} seconds, you slow down and are able", "to cast up to {count} fireballs by left clicking.", "", "Fireballs deal &c{damage} &7damage upon contact", "and ignite your target for &c{ignite} &7seconds.", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("duration", new LinearValue(8, 0));
- addModifier("count", new LinearValue(4, 0));
- addModifier("mana", new LinearValue(15, 1));
- addModifier("damage", new LinearValue(5, 3));
- addModifier("ignite", new LinearValue(2, .1));
- addModifier("cooldown", new LinearValue(9, -.1, 1, 5));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- SkillResult cast = new SkillResult(data, skill);
- if (!cast.isSuccessful())
- return cast;
-
- new Rage(data, cast);
- return cast;
- }
-
- public static class Rage extends BukkitRunnable implements Listener {
- private final PlayerData data;
- private final int count, ignite;
- private final double damage;
-
- private int c;
- private double b;
- private long last = System.currentTimeMillis();
-
- /*
- * time the player needs to wait before firing two fireballs.
- */
- private static final long timeOut = 700;
-
- public Rage(PlayerData data, SkillResult cast) {
- this.data = data;
- this.ignite = (int) (20 * cast.getModifier("ignite"));
- this.damage = cast.getModifier("damage");
- c = count = (int) cast.getModifier("count");
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- Bukkit.getScheduler().runTaskLater(MMOCore.plugin, this::close, (long) (cast.getModifier("duration") * 20));
- runTaskTimer(MMOCore.plugin, 0, 1);
-
- if(data.isOnline()) {
- data.getPlayer().removePotionEffect(PotionEffectType.SLOW);
- data.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.SLOW, (int) (cast.getModifier("duration") * 20), 1));
- }
- }
-
- @EventHandler
- public void a(PlayerInteractEvent event) {
- if(!data.isOnline()) return;
- if (event.getPlayer().equals(data.getPlayer()) && event.getAction().name().contains("LEFT_CLICK") && (System.currentTimeMillis() - last) > timeOut) {
- last = System.currentTimeMillis();
- castEffect();
- fireball(c < 2);
- if (c-- < 2)
- close();
- }
- }
-
- private void castEffect() {
- if(!data.isOnline()) return;
- VectorRotation rotation = new VectorRotation(data.getPlayer().getEyeLocation());
- for (double a = 0; a < Math.PI * 2; a += Math.PI / 13) {
- Vector vec = rotation.rotate(new Vector(Math.cos(a), Math.sin(a), 0)).add(data.getPlayer().getEyeLocation().getDirection().multiply(.5)).multiply(.3);
- data.getPlayer().getWorld().spawnParticle(Particle.FLAME, data.getPlayer().getLocation().add(0, 1.3, 0).add(data.getPlayer().getEyeLocation().getDirection().multiply(.5)), 0, vec.getX(), vec.getY(), vec.getZ(), .3);
- }
- }
-
- private void close() {
- if (isCancelled())
- return;
-
- cancel();
- HandlerList.unregisterAll(this);
- }
-
- private void fireball(boolean last) {
- if(!data.isOnline()) return;
- if (last) {
- data.getPlayer().removePotionEffect(PotionEffectType.SLOW);
- data.getPlayer().removePotionEffect(PotionEffectType.SLOW);
- }
-
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 1, last ? 0 : 1);
- new BukkitRunnable() {
- int j = 0;
- final Vector vec = data.getPlayer().getEyeLocation().getDirection();
- final Location loc = data.getPlayer().getLocation().add(0, 1.3, 0);
-
- public void run() {
- if (j++ > 40)
- cancel();
-
- loc.add(vec);
-
- if (j % 2 == 0)
- loc.getWorld().playSound(loc, Sound.BLOCK_FIRE_AMBIENT, 2, 1);
- loc.getWorld().spawnParticle(Particle.FLAME, loc, 4, .1, .1, .1, 0);
- loc.getWorld().spawnParticle(Particle.LAVA, loc, 0);
-
- for (Entity target : MMOCoreUtils.getNearbyChunkEntities(loc))
- if (MythicLib.plugin.getVersion().getWrapper().isInBoundingBox(target, loc) && MMOCoreUtils.canTarget(data, target)) {
- loc.getWorld().spawnParticle(Particle.LAVA, loc, 8);
- loc.getWorld().spawnParticle(Particle.FLAME, loc, 32, 0, 0, 0, .1);
- loc.getWorld().playSound(loc, Sound.ENTITY_BLAZE_HURT, 2, 1);
- target.setFireTicks(target.getFireTicks() + ignite);
- MythicLib.plugin.getDamage().damage(data.getPlayer(), (LivingEntity) target, new AttackResult(damage, DamageType.SKILL, DamageType.PROJECTILE, DamageType.MAGIC));
- cancel();
- }
- }
- }.runTaskTimer(MMOCore.plugin, 0, 1);
- }
-
- @Override
- public void run() {
- if (data.getPlayer().isDead() || !data.getPlayer().isOnline()) {
- close();
- return;
- }
-
- b += Math.PI / 30;
- for (int j = 0; j < c; j++) {
- double a = Math.PI * 2 * j / count + b;
- data.getPlayer().spawnParticle(Particle.FLAME, data.getPlayer().getLocation().add(Math.cos(a) * 1.5, 1 + Math.sin(a * 1.5) * .7, Math.sin(a) * 1.5), 0);
- }
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Fireball.java b/src/main/java/net/Indyuce/mmocore/skill/Fireball.java
deleted file mode 100644
index 239ddde0..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Fireball.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.api.MMORayTraceResult;
-import io.lumine.mythic.lib.version.VersionMaterial;
-import io.lumine.mythic.lib.version.VersionSound;
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.MMOCoreUtils;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import org.bukkit.Location;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.scheduler.BukkitRunnable;
-import org.bukkit.util.Vector;
-
-public class Fireball extends Skill {
- public Fireball() {
- super();
- setMaterial(VersionMaterial.FIRE_CHARGE.toMaterial());
- setLore("Casts a deadly fireball onto your", "target, dealing &c{damage} &7damage upon contact", "and igniting it for &c{ignite} &7seconds.", "", "Shatters into 3 blazing hot shards which stick", "to walls and explode 3 seconds later, dealing", "&c{ratio}% &7of the initial spell damage.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("mana", new LinearValue(15, 1));
- addModifier("damage", new LinearValue(5, 3));
- addModifier("ignite", new LinearValue(2, .1));
- addModifier("ratio", new LinearValue(50, 3));
- addModifier("cooldown", new LinearValue(9, -.1, 1, 5));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- SkillResult cast = new SkillResult(data, skill);
- if (!cast.isSuccessful() || !data.isOnline())
- return cast;
-
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 1, 1);
- new BukkitRunnable() {
- int j = 0;
- final Vector vec = data.getPlayer().getEyeLocation().getDirection();
- final Location loc = data.getPlayer().getLocation().add(0, 1.3, 0);
-
- public void run() {
- if (j++ > 40) {
- cancel();
- return;
- }
-
- loc.add(vec);
-
- if (j % 3 == 0)
- loc.getWorld().playSound(loc, Sound.BLOCK_FIRE_AMBIENT, 2, 1);
- loc.getWorld().spawnParticle(Particle.FLAME, loc, 4, .02, .02, .02, 0);
- loc.getWorld().spawnParticle(Particle.LAVA, loc, 0);
-
- for (Entity target : MMOCoreUtils.getNearbyChunkEntities(loc))
- if (MythicLib.plugin.getVersion().getWrapper().isInBoundingBox(target, loc) && MMOCoreUtils.canTarget(data, target)) {
- loc.getWorld().spawnParticle(Particle.LAVA, loc, 8);
- loc.getWorld().spawnParticle(Particle.FLAME, loc, 32, 0, 0, 0, .1);
- loc.getWorld().playSound(loc, Sound.ENTITY_BLAZE_HURT, 2, 1);
- target.setFireTicks((int) (target.getFireTicks() + cast.getModifier("ignite") * 20));
- double damage = cast.getModifier("damage");
- MythicLib.plugin.getDamage().damage(data.getPlayer(), (LivingEntity) target, new AttackResult(damage, DamageType.SKILL, DamageType.PROJECTILE, DamageType.MAGIC));
-
- new BukkitRunnable() {
- int i = 0;
-
- @Override
- public void run() {
- if (i++ > 2) {
- cancel();
- return;
- }
-
- double range = 2.5 * (1 + random.nextDouble());
- Vector dir = randomDirection();
- loc.getWorld().playSound(loc, Sound.ENTITY_BLAZE_HURT, 2, 1.5f);
-
- MMORayTraceResult result = MythicLib.plugin.getVersion().getWrapper().rayTrace(loc, dir, range, entity -> MMOCoreUtils.canTarget(data, entity));
- if (result.hasHit())
- MythicLib.plugin.getDamage().damage(data.getPlayer(), result.getHit(), new AttackResult(damage, DamageType.SKILL, DamageType.PROJECTILE, DamageType.MAGIC));
- result.draw(loc.clone(), dir, 8, tick -> tick.getWorld().spawnParticle(Particle.FLAME, tick, 0));
-
- }
- }.runTaskTimer(MMOCore.plugin, 3, 3);
-
- cancel();
- return;
- }
- }
- }.runTaskTimer(MMOCore.plugin, 0, 1);
- return cast;
- }
-
- private Vector randomDirection() {
- double x = random.nextDouble() - .5, y = (random.nextDouble() - .2) / 2, z = random.nextDouble() - .5;
- Vector dir = new Vector(x, y, z);
- return dir.lengthSquared() == 0 ? new Vector(1, 0, 0) : dir.normalize();
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Furtive_Strike.java b/src/main/java/net/Indyuce/mmocore/skill/Furtive_Strike.java
deleted file mode 100644
index 613fe3ac..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Furtive_Strike.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.LivingEntity;
-
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
-
-public class Furtive_Strike extends Skill {
- public Furtive_Strike() {
- super();
- setMaterial(Material.COAL);
- setLore("Deals &c{damage} &7damage, increased by &c{extra}% &7if", "there are not any enemies within &c{radius} &7blocks.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(20, -.1, 5, 20));
- addModifier("mana", new LinearValue(8, 3));
- addModifier("damage", new LinearValue(5, 1.5));
- addModifier("extra", new LinearValue(50, 20));
- addModifier("radius", new LinearValue(7, 0));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- TargetSkillResult cast = new TargetSkillResult(data, skill, 3);
- if (!cast.isSuccessful() || !data.isOnline())
- return cast;
-
- LivingEntity target = cast.getTarget();
- target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 2, 1.5f);
- target.getWorld().spawnParticle(Particle.CRIT, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, .5);
- target.getWorld().spawnParticle(Particle.SMOKE_NORMAL, target.getLocation().add(0, target.getHeight() / 2, 0), 64, 0, 0, 0, .08);
-
- double damage = cast.getModifier("damage");
-
- double radius = cast.getModifier("radius");
- if (target.getNearbyEntities(radius, radius, radius).stream().allMatch(entity -> entity.equals(data.getPlayer()))) {
- new SmallParticleEffect(target, Particle.SPELL_WITCH);
- damage *= 1 + cast.getModifier("extra") / 100;
- }
-
- MythicLib.plugin.getDamage().damage(data.getPlayer(), target, new AttackResult(damage, DamageType.SKILL, DamageType.PHYSICAL));
- return cast;
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Greater_Healings.java b/src/main/java/net/Indyuce/mmocore/skill/Greater_Healings.java
deleted file mode 100644
index 0a2ddcb1..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Greater_Healings.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.attribute.Attribute;
-import org.bukkit.entity.LivingEntity;
-
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
-
-public class Greater_Healings extends Skill {
- public Greater_Healings() {
- super();
- setMaterial(Material.GOLDEN_APPLE);
- setLore("Instantly grants &a{heal} &7HP to the", "target. Sneak to cast it on yourself.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("mana", new LinearValue(4, 2));
- addModifier("heal", new LinearValue(10, 4));
- addModifier("cooldown", new LinearValue(9, -.1, 1, 5));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- SkillResult cast = data.getPlayer().isSneaking() ? new SkillResult(data, skill) : new TargetSkillResult(data, skill, 50, true);
- if (!cast.isSuccessful())
- return cast;
-
- LivingEntity target = cast instanceof TargetSkillResult ? ((TargetSkillResult) cast).getTarget() : data.getPlayer();
-
- double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
- target.setHealth(Math.min(max, target.getHealth() + cast.getModifier("heal")));
-
- new SmallParticleEffect(target, Particle.HEART, 1);
- target.getWorld().playSound(target.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 2, 2);
- return cast;
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Human_Shield.java b/src/main/java/net/Indyuce/mmocore/skill/Human_Shield.java
deleted file mode 100644
index 380459fd..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Human_Shield.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.attribute.Attribute;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.Listener;
-import org.bukkit.event.entity.EntityDamageEvent;
-import org.bukkit.scheduler.BukkitRunnable;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.version.VersionMaterial;
-
-public class Human_Shield extends Skill {
- public Human_Shield() {
- super();
- setMaterial(VersionMaterial.TOTEM_OF_UNDYING.toMaterial());
- setLore("Casts a protection charm onto target ally,", "reducing damage taken by &a{reduction}%&7.", "&a{redirect}% &7of this damage is redirected to you.", "Charm is cancelled when reaching &c{low}%&7 health.", "Lasts &a{duration} &7seconds.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(18, -.3, 14, 18));
- addModifier("mana", new LinearValue(15, 1.5));
- addModifier("reduction", new LinearValue(30, 3, 30, 70));
- addModifier("redirect", new LinearValue(30, -2, 20, 30));
- addModifier("duration", new LinearValue(7, 0));
- addModifier("low", new LinearValue(10, 0));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- TargetSkillResult cast = new TargetSkillResult(data, skill, 7, true);
- if (!cast.isSuccessful())
- return cast;
-
- if (!(cast.getTarget() instanceof Player)) {
- cast.abort();
- return cast;
- }
-
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), Sound.ENTITY_BLAZE_AMBIENT, 1, 1);
- new HumanShield(data, (Player) cast.getTarget(), cast.getModifier("reduction"), cast.getModifier("redirect"), cast.getModifier("duration"), cast.getModifier("low"));
- return cast;
- }
-
- public static class HumanShield extends BukkitRunnable implements Listener {
- private final PlayerData data;
- private final Player target;
- private final double r, rd, d, l;
-
- private int j;
-
- public HumanShield(PlayerData data, Player target, double reduction, double redirect, double duration, double low) {
- this.target = target;
- this.data = data;
-
- r = 1 - Math.min(1, reduction / 100);
- rd = redirect / 100;
- d = duration * 20;
- l = low / 100;
-
- runTaskTimer(MMOCore.plugin, 0, 1);
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- @EventHandler
- public void a(EntityDamageEvent event) {
- if (event.getEntity().equals(target)) {
-
- double damage = event.getDamage() * r;
- event.setDamage(damage);
-
- double health = data.getPlayer().getHealth() - damage * rd;
- if (health > data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue() * l)
- data.getPlayer().setHealth(health);
- else {
- data.getPlayer().setHealth(1);
- close();
- }
- }
- }
-
- @Override
- public void run() {
- if (!data.isOnline() || data.getPlayer().isDead() || !target.isOnline() || target.isDead() || j++ >= d) {
- close();
- return;
- }
-
- double a = (double) j / 5;
- target.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, target.getLocation().add(Math.cos(a), 1 + Math.sin(a / 3) / 1.3, Math.sin(a)), 0);
- }
-
- private void close() {
- cancel();
- HandlerList.unregisterAll(this);
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Ice_Spikes.java b/src/main/java/net/Indyuce/mmocore/skill/Ice_Spikes.java
deleted file mode 100644
index ff28852f..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Ice_Spikes.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Location;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
-import org.bukkit.scheduler.BukkitRunnable;
-import org.bukkit.util.Vector;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.LocationSkillResult;
-import net.Indyuce.mmocore.api.util.MMOCoreUtils;
-import net.Indyuce.mmocore.api.util.math.Line3D;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.version.VersionMaterial;
-
-public class Ice_Spikes extends Skill {
- private static final double radius = 3;
-
- public Ice_Spikes() {
- super();
- setMaterial(VersionMaterial.SNOWBALL.toMaterial());
- setLore("Ice spikes summon from the ground", "and shatter, each dealing &9{damage} &7damage", "to hit enemies and slowing them down", "for &9{slow} &7seconds.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(6, -.1, 2, 6));
- addModifier("mana", new LinearValue(20, 2));
- addModifier("damage", new LinearValue(3, 1));
- addModifier("slow", new LinearValue(4, 0));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- LocationSkillResult cast = new LocationSkillResult(data, skill, 20);
- if (!cast.isSuccessful() || !data.isOnline())
- return cast;
-
- Location loc = cast.getHit();
- double damage = cast.getModifier("damage");
- int slow = (int) (20 * cast.getModifier("slow"));
-
- new BukkitRunnable() {
- int j = 0;
-
- @Override
- public void run() {
-
- if (j++ > 8) {
- cancel();
- return;
- }
-
- Location loc1 = loc.clone().add(offset() * radius, 0, offset() * radius).add(0, 2, 0);
- loc.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc1, 32, 0, 2, 0, 0);
- loc.getWorld().spawnParticle(Particle.SNOWBALL, loc1, 32, 0, 2, 0, 0);
- loc.getWorld().playSound(loc1, Sound.BLOCK_GLASS_BREAK, 2, 0);
-
- Line3D line = new Line3D(loc.toVector(), loc.toVector().add(new Vector(0, 1, 0)));
- for (Entity entity : MMOCoreUtils.getNearbyChunkEntities(loc1))
- if (line.distanceSquared(entity.getLocation().toVector()) < radius && Math.abs(entity.getLocation().getY() - loc1.getY()) < 10 && MMOCoreUtils.canTarget(data, entity)) {
- MythicLib.plugin.getDamage().damage(data.getPlayer(), (LivingEntity) entity, new AttackResult(damage, DamageType.SKILL, DamageType.MAGIC));
- ((LivingEntity) entity).addPotionEffect(new PotionEffect(PotionEffectType.SLOW, slow, 0));
- }
- }
- }.runTaskTimer(MMOCore.plugin, 0, 5);
- return cast;
- }
-
- private double offset() {
- return random.nextDouble() * (random.nextBoolean() ? 1 : -1);
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Minor_Healings.java b/src/main/java/net/Indyuce/mmocore/skill/Minor_Healings.java
deleted file mode 100644
index 44f23cbc..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Minor_Healings.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.attribute.Attribute;
-import org.bukkit.entity.LivingEntity;
-
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
-
-public class Minor_Healings extends Skill {
- public Minor_Healings() {
- super();
- setMaterial(Material.GOLDEN_APPLE);
- setLore("Instantly grants &a{heal} &7HP to the", "target. Sneak to cast it on yourself.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("mana", new LinearValue(4, 2));
- addModifier("heal", new LinearValue(4, 2));
- addModifier("cooldown", new LinearValue(9, -.1, 1, 5));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- SkillResult cast = data.getPlayer().isSneaking() ? new SkillResult(data, skill) : new TargetSkillResult(data, skill, 50, true);
- if (!cast.isSuccessful())
- return cast;
-
- LivingEntity target = cast instanceof TargetSkillResult ? ((TargetSkillResult) cast).getTarget() : data.getPlayer();
-
- double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
- target.setHealth(Math.min(max, target.getHealth() + cast.getModifier("heal")));
-
- new SmallParticleEffect(target, Particle.HEART, 1);
- target.getWorld().playSound(target.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 2, 2);
- return cast;
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/PassiveSkill.java b/src/main/java/net/Indyuce/mmocore/skill/PassiveSkill.java
new file mode 100644
index 00000000..acb7894b
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/PassiveSkill.java
@@ -0,0 +1,19 @@
+package net.Indyuce.mmocore.skill;
+
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.event.Listener;
+
+public class PassiveSkill extends Skill implements Listener {
+ public PassiveSkill() {
+ super();
+ }
+
+ public PassiveSkill(String id) {
+ super(id);
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata casterMeta, SkillInfo skill) {
+ return new SkillMetadata(casterMeta, skill);
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/api/skill/PlayerSkillData.java b/src/main/java/net/Indyuce/mmocore/skill/PlayerSkillData.java
similarity index 50%
rename from src/main/java/net/Indyuce/mmocore/api/skill/PlayerSkillData.java
rename to src/main/java/net/Indyuce/mmocore/skill/PlayerSkillData.java
index 6e6afce4..ed08851a 100644
--- a/src/main/java/net/Indyuce/mmocore/api/skill/PlayerSkillData.java
+++ b/src/main/java/net/Indyuce/mmocore/skill/PlayerSkillData.java
@@ -1,11 +1,13 @@
-package net.Indyuce.mmocore.api.skill;
+package net.Indyuce.mmocore.skill;
import java.util.HashMap;
import java.util.Map;
+import io.lumine.mythic.utils.cooldown.CooldownMap;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill.SkillInfo;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
import net.Indyuce.mmocore.comp.mythicmobs.skill.MythicMobSkill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
/**
* Note: any method which return longs returns milliseconds.
@@ -16,15 +18,6 @@ public class PlayerSkillData {
private final Map cooldowns = new HashMap<>();
private final PlayerData data;
- /**
- * MythicMobs skill damage is handled via math formula which can retrieve
- * PAPI placeholders. When a skill is cast, all skill modifiers are cached
- * into that map: 1- for easier and faster access 2- it removes interference
- * for example when stats are calculating not when the spell is cast but
- * rather when the spell hits
- */
- private final Map cache = new HashMap<>();
-
public PlayerSkillData(PlayerData data) {
this.data = data;
}
@@ -82,66 +75,4 @@ public class PlayerSkillData {
long reduction = (long) (relative ? value * (double) getCooldown(skill) : value * 1000.);
cooldowns.put(skill.getSkill().getId(), lastCast(skill.getSkill()) + reduction);
}
-
- public double getCachedModifier(String name) {
- return cache.containsKey(name) ? cache.get(name).getValue() : 0;
- }
-
- public void cacheModifiers(MythicMobSkill skill, SkillResult cast) {
- cacheModifiers(skill.getInternalName(), cast);
- }
-
- /**
- * Caches all modifiers from a cast skill in the map
- *
- * @param skill
- * Skill identifier being used as reference in the map
- * @param cast
- * Skill being cast
- */
- public void cacheModifiers(String skill, SkillResult cast) {
- for (String modifier : cast.getSkill().getModifiers())
- cacheModifier(skill, modifier, cast.getModifier(modifier));
-
- cacheModifier(skill, "level", cast.getLevel());
- }
-
- /**
- * Caches a specific modifier
- *
- * @param skill
- * The identifier of the skill being cast
- * @param name
- * Modifier name
- * @param value
- * Modifier value
- */
- public void cacheModifier(String skill, String name, double value) {
- cache.put(skill + "." + name, new CachedModifier(value));
- }
-
- /**
- * Empties cached modifiers. Modifiers should time out one minute after the
- * skill was cast
- */
- public void refresh() {
- cache.values().removeIf(CachedModifier::isTimedOut);
- }
-
- public static class CachedModifier {
- private final long date = System.currentTimeMillis();
- private final double value;
-
- public CachedModifier(double value) {
- this.value = value;
- }
-
- public boolean isTimedOut() {
- return date + 1000 * 60 < System.currentTimeMillis();
- }
-
- public double getValue() {
- return value;
- }
- }
}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Power_Mark.java b/src/main/java/net/Indyuce/mmocore/skill/Power_Mark.java
deleted file mode 100644
index affa38d6..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Power_Mark.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Color;
-import org.bukkit.Location;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
-import org.bukkit.scheduler.BukkitRunnable;
-import org.bukkit.util.Vector;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.MMOCoreUtils;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
-import io.lumine.mythic.lib.MythicLib;
-import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
-import io.lumine.mythic.lib.version.VersionMaterial;
-import io.lumine.mythic.lib.version.VersionSound;
-
-public class Power_Mark extends Skill implements Listener {
- public Power_Mark() {
- super();
- setMaterial(VersionMaterial.WITHER_SKELETON_SKULL.toMaterial());
- setLore("Attacking an enemy applies a deadly", "magical mark which spreads accross the", "ground. This mark accumulates &6{ratio}%", "of the damage dealt to the initial", "target over &6{duration} &7seconds.", "", "After this duration, the mark bursts, dealing", "accumulated damage to nearby enemies and", "stunning them for &6{stun}+ &7seconds.", "", "The more damage, the longer the stun.", "", "&e{cooldown}s Cooldown");
- setPassive();
-
- addModifier("stun", new LinearValue(.4, .03));
- addModifier("ratio", new LinearValue(10, 5));
- addModifier("duration", new LinearValue(10, .1));
- addModifier("cooldown", new LinearValue(30, 0));
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- @EventHandler
- public void a(PlayerAttackEvent event) {
- PlayerData data = PlayerData.get(event.getData().getUniqueId());
- if (!event.getAttack().hasType(DamageType.WEAPON) || !data.getProfess().hasSkill(this))
- return;
-
- SkillResult cast = data.cast(this);
- if (!cast.isSuccessful())
- return;
-
- new PowerMark(data, cast, event.getEntity().getLocation());
- }
-
- public class PowerMark extends BukkitRunnable implements Listener {
- private final PlayerData data;
- private final Location loc;
-
- private final double duration;
- private final double ratio;
- private double stun;
-
- private double accumulate;
- private int j;
-
- public PowerMark(PlayerData data, SkillResult cast, Location loc) {
- this.data = data;
- this.loc = loc;
-
- loc.getWorld().playSound(loc, Sound.BLOCK_END_PORTAL_FRAME_FILL, 2, 1);
-
- duration = cast.getModifier("duration");
- ratio = cast.getModifier("ratio") / 100;
- stun = cast.getModifier("stun");
-
- runTaskTimer(MMOCore.plugin, 0, 1);
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- private void unregister() {
- PlayerAttackEvent.getHandlerList().unregister(this);
- cancel();
- }
-
- @EventHandler(priority = EventPriority.HIGHEST)
- public void stackDamage(PlayerAttackEvent event) {
- if (!event.isCancelled() && j < 20 * (duration - 2) && radiusCheck(event.getEntity().getLocation()) && PlayerData.get(event.getData().getUniqueId()).equals(data)) {
- accumulate += event.getAttack().getDamage() * ratio;
- new ParabolicProjectile(event.getEntity().getLocation().add(0, event.getEntity().getHeight() / 2, 0), loc, () -> loc.getWorld().playSound(loc, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1), Color.PURPLE);
- }
- }
-
- private boolean radiusCheck(Location loc) {
- return loc.getWorld().equals(this.loc.getWorld()) && loc.distanceSquared(this.loc) < 16;
- }
-
- @Override
- public void run() {
- if(!data.isOnline()) return;
- if (j++ > duration * 20) {
- unregister();
-
- for (double a = 0; a < Math.PI * 2; a += Math.PI * 2 / 17)
- new ParabolicProjectile(loc, loc.clone().add(6 * Math.cos(a), 0, 6 * Math.sin(a)), Particle.SPELL_WITCH);
-
- loc.getWorld().playSound(loc, Sound.ENTITY_GENERIC_EXPLODE, 2, 0);
- loc.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, loc.clone().add(0, 1, 0), 16, 2, 2, 2, 0);
- loc.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, loc.clone().add(0, 1, 0), 24, 0, 0, 0, .3f);
-
- stun += Math.log(Math.max(1, accumulate - 10)) / 8;
-
- for (Entity entity : MMOCoreUtils.getNearbyChunkEntities(loc))
- if (entity.getLocation().distanceSquared(loc) < 25 && MMOCoreUtils.canTarget(data, entity)) {
- ((LivingEntity) entity).addPotionEffect(new PotionEffect(PotionEffectType.SLOW, (int) (stun * 20), 10, false, false));
- MythicLib.plugin.getDamage().damage(data.getPlayer(), (LivingEntity) entity, new AttackResult(accumulate, DamageType.SKILL, DamageType.MAGIC));
- entity.setVelocity(format(entity.getLocation().subtract(loc).toVector().setY(0)).setY(.3));
- }
- return;
- }
-
- if (j % 2 == 0 && j > 20 * (duration - 2))
- loc.getWorld().playSound(loc, VersionSound.BLOCK_NOTE_BLOCK_PLING.toSound(), 1, (float) (1 + (j - 20 * (duration - 2)) / 40));
-
- double a = (double) j / 16;
- double r = Math.sqrt(Math.min(duration * 2 - (double) j / 10, 4)) * 2;
- for (double k = 0; k < Math.PI * 2; k += Math.PI * 2 / 5)
- loc.getWorld().spawnParticle(Particle.SPELL_WITCH, loc.clone().add(r * Math.cos(k + a), 0, r * Math.sin(k + a)), 0);
- }
- }
-
- private Vector format(Vector vec) {
- return vec.length() < .01 ? new Vector(0, 0, 0) : vec.normalize();
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/api/skill/Skill.java b/src/main/java/net/Indyuce/mmocore/skill/Skill.java
similarity index 96%
rename from src/main/java/net/Indyuce/mmocore/api/skill/Skill.java
rename to src/main/java/net/Indyuce/mmocore/skill/Skill.java
index 796386ed..b2f46550 100644
--- a/src/main/java/net/Indyuce/mmocore/api/skill/Skill.java
+++ b/src/main/java/net/Indyuce/mmocore/skill/Skill.java
@@ -1,9 +1,10 @@
-package net.Indyuce.mmocore.api.skill;
+package net.Indyuce.mmocore.skill;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
@@ -133,12 +134,7 @@ public abstract class Skill {
return current instanceof IntegerLinearValue ? new IntegerLinearValue(config) : new LinearValue(config);
}
- /*
- * not overriden for passive skills therefore not abstract.
- */
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- return new SkillResult(data, skill);
- }
+ public abstract SkillMetadata whenCast(CasterMetadata casterMeta, SkillInfo skill);
public SkillInfo newSkillInfo(ConfigurationSection config) {
return new SkillInfo(config);
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Sneaky_Picky.java b/src/main/java/net/Indyuce/mmocore/skill/Sneaky_Picky.java
deleted file mode 100644
index 39c9cea5..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Sneaky_Picky.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import io.lumine.mythic.lib.api.DamageType;
-import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
-
-public class Sneaky_Picky extends Skill implements Listener {
- public Sneaky_Picky() {
- super();
- setMaterial(Material.DIAMOND_SWORD);
- setLore("Your attack is empowered by &f{extra}% &7when", "delivering the first blow during a fight.", "", "&9Costs {mana} {mana_name}");
- setPassive();
-
- addModifier("cooldown", new LinearValue(0, 0));
- addModifier("mana", new LinearValue(8, 1));
- addModifier("extra", new LinearValue(50, 20));
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- @EventHandler
- public void a(PlayerAttackEvent event) {
- PlayerData data = PlayerData.get(event.getData().getUniqueId());
- if (!event.getAttack().hasType(DamageType.WEAPON) || data.isInCombat() || !data.getProfess().hasSkill(this))
- return;
-
- SkillResult cast = data.cast(this);
- if (!cast.isSuccessful())
- return;
-
- data.cast(cast.getInfo());
-
- event.getAttack().multiplyDamage(1 + cast.getModifier("extra") / 100);
- LivingEntity target = event.getEntity();
- target.getWorld().spawnParticle(Particle.SMOKE_NORMAL, target.getLocation().add(0, target.getHeight() / 2, 0), 64, 0, 0, 0, .05);
- target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 1, 2);
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Telekinesy.java b/src/main/java/net/Indyuce/mmocore/skill/Telekinesy.java
deleted file mode 100644
index 476f47ca..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Telekinesy.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Location;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.entity.Entity;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerInteractEvent;
-import org.bukkit.scheduler.BukkitRunnable;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
-import io.lumine.mythic.lib.version.VersionMaterial;
-import io.lumine.mythic.lib.version.VersionSound;
-
-public class Telekinesy extends Skill {
- public Telekinesy() {
- super();
- setMaterial(VersionMaterial.MAGENTA_DYE.toMaterial());
- setLore("You take the control over your target", "for &9{duration} &7seconds. Left click to throw him.", "Knockback force: &f{knockback}%", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(20, -.3, 10, 20));
- addModifier("mana", new LinearValue(20, 2));
- addModifier("knockback", new LinearValue(50, 10));
- addModifier("duration", new LinearValue(3, .1, 3, 6));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- TargetSkillResult cast = new TargetSkillResult(data, skill, 7);
- if (!cast.isSuccessful() || !data.isOnline())
- return cast;
-
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 1);
- new TelekinesyRunnable(data, cast.getTarget(), cast.getModifier("duration"), cast.getModifier("knockback") / 100);
- return cast;
- }
-
- public static class TelekinesyRunnable extends BukkitRunnable implements Listener {
- private final Entity entity;
- private final PlayerData data;
-
- private final long duration;
- private final double d, f;
-
- private int j;
-
- public TelekinesyRunnable(PlayerData data, Entity entity, double duration, double force) {
- this.entity = entity;
- this.data = data;
-
- d = data.getPlayer().getLocation().distance(entity.getLocation());
- f = force;
- this.duration = (long) (20 * duration);
-
- runTaskTimer(MMOCore.plugin, 0, 1);
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- }
-
- @EventHandler
- public void a(PlayerInteractEvent event) {
- if(!data.isOnline()) return;
- if (event.getPlayer().equals(data.getPlayer()) && event.getAction().name().contains("LEFT_CLICK")) {
- entity.setVelocity(data.getPlayer().getEyeLocation().getDirection().multiply(1.5 * f));
- entity.getWorld().playSound(entity.getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, 1);
- entity.getWorld().spawnParticle(Particle.SPELL_WITCH, entity.getLocation().add(0, entity.getHeight() / 2, 0), 16);
- close();
- }
- }
-
- @Override
- public void run() {
- if (!data.isOnline() || entity.isDead() || j++ >= duration) {
- close();
- return;
- }
-
- if (j % 8 == 0)
- new ParabolicProjectile(data.getPlayer().getEyeLocation(), entity.getLocation().add(0, entity.getHeight() / 2, 0), Particle.SPELL_WITCH);
-
- Location loc = data.getPlayer().getEyeLocation().add(data.getPlayer().getEyeLocation().getDirection().multiply(d));
- entity.setVelocity(loc.subtract(entity.getLocation().add(0, entity.getHeight() / 2, 0)).toVector().multiply(2));
- entity.setFallDistance(0);
- }
-
- private void close() {
- cancel();
- HandlerList.unregisterAll(this);
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Warp.java b/src/main/java/net/Indyuce/mmocore/skill/Warp.java
deleted file mode 100644
index 4ec1b82d..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Warp.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Location;
-import org.bukkit.Material;
-import org.bukkit.Particle;
-import org.bukkit.Sound;
-import org.bukkit.block.Block;
-
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
-import io.lumine.mythic.lib.version.VersionSound;
-
-public class Warp extends Skill {
- public Warp() {
- super();
- setMaterial(Material.ENDER_PEARL);
- setLore("Teleports you to target location.", "Max. Range: &5{range}", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(15, -.3, 2, 15));
- addModifier("mana", new LinearValue(8, 3));
- addModifier("range", new LinearValue(16, 1, 0, 100));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- WarpCast cast = new WarpCast(data, skill);
- if (!cast.isSuccessful() || !data.isOnline())
- return cast;
-
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 2);
-
- Location loc = cast.block.getLocation().add(0, 1, 0);
- loc.setYaw(data.getPlayer().getLocation().getYaw());
- loc.setPitch(data.getPlayer().getLocation().getPitch());
-
- new ParabolicProjectile(data.getPlayer().getLocation().add(0, 1, 0), loc.clone().add(0, 1, 0), () -> {
- if (data.getPlayer().isOnline() && !data.getPlayer().isDead()) {
- data.getPlayer().teleport(loc);
- data.getPlayer().getWorld().spawnParticle(Particle.EXPLOSION_LARGE, data.getPlayer().getLocation().add(0, 1, 0), 0);
- data.getPlayer().getWorld().spawnParticle(Particle.SPELL_INSTANT, data.getPlayer().getLocation().add(0, 1, 0), 32, 0, 0, 0, .1);
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), VersionSound.ENTITY_ENDERMAN_TELEPORT.toSound(), 1, 1);
- }
- }, 2, Particle.SPELL_INSTANT);
- return cast;
- }
-
- private class WarpCast extends SkillResult {
- private Block block;
-
- public WarpCast(PlayerData data, SkillInfo skill) {
- super(data, skill);
- if(!data.isOnline()) abort();
- else if (isSuccessful() && (block = data.getPlayer().getTargetBlock(null, (int) getModifier("range"))) == null)
- abort();
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Weaken.java b/src/main/java/net/Indyuce/mmocore/skill/Weaken.java
deleted file mode 100644
index e2a42cc9..00000000
--- a/src/main/java/net/Indyuce/mmocore/skill/Weaken.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.Indyuce.mmocore.skill;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Particle;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.entity.EntityDamageByEntityEvent;
-import org.bukkit.util.Vector;
-
-import net.Indyuce.mmocore.MMOCore;
-import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
-import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
-import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
-import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
-import io.lumine.mythic.lib.version.VersionMaterial;
-
-public class Weaken extends Skill {
- public Weaken() {
- super();
- setMaterial(VersionMaterial.MAGENTA_DYE.toMaterial());
- setLore("The target is weakened for", "&8{duration} &7seconds and is dealt", "&7extra &8{ratio}% &7damage.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
-
- addModifier("cooldown", new LinearValue(20, -.1, 5, 20));
- addModifier("mana", new LinearValue(4, 1));
- addModifier("ratio", new LinearValue(30, 3));
- addModifier("duration", new LinearValue(10, -.1, 5, 10));
- }
-
- @Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- TargetSkillResult cast = new TargetSkillResult(data, skill, 7);
- if (!cast.isSuccessful() || !data.isOnline())
- return cast;
-
- LivingEntity target = cast.getTarget();
- new ParabolicProjectile(data.getPlayer().getLocation().add(0, 1, 0), target.getLocation().add(0, target.getHeight() / 2, 0), randomVector(data.getPlayer()), () -> {
- if (!target.isDead())
- new Weakened(target, cast.getModifier("ratio"), cast.getModifier("duration"));
- }, 2, Particle.SPELL_WITCH);
- return cast;
- }
-
- private Vector randomVector(Player player) {
- double a = Math.toRadians(player.getEyeLocation().getYaw() + 90);
- a += (random.nextBoolean() ? 1 : -1) * (random.nextDouble() + .5) * Math.PI / 6;
- return new Vector(Math.cos(a), .8, Math.sin(a)).normalize().multiply(.4);
- }
-
- public static class Weakened implements Listener {
- private final Entity entity;
- private final double c;
-
- public Weakened(Entity entity, double ratio, double duration) {
- this.entity = entity;
- this.c = 1 + ratio / 100;
-
- new SmallParticleEffect(entity, Particle.SPELL_WITCH);
-
- Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
- Bukkit.getScheduler().scheduleSyncDelayedTask(MMOCore.plugin, () -> EntityDamageByEntityEvent.getHandlerList().unregister(this), (int) duration * 20);
- }
-
- @EventHandler
- public void a(EntityDamageByEntityEvent event) {
- if (event.getEntity().equals(entity)) {
- event.getEntity().getWorld().spawnParticle(Particle.SPELL_WITCH, entity.getLocation().add(0, entity.getHeight() / 2, 0), 16, .5, .5, .5, 0);
- event.setDamage(event.getDamage() * c);
- }
- }
- }
-}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Ambers.java b/src/main/java/net/Indyuce/mmocore/skill/list/Ambers.java
new file mode 100644
index 00000000..dcc8dd75
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Ambers.java
@@ -0,0 +1,88 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import io.lumine.mythic.lib.damage.DamageType;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.player.stats.StatType;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
+import net.Indyuce.mmocore.skill.PassiveSkill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.*;
+import org.bukkit.event.EventHandler;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class Ambers extends PassiveSkill {
+ public Ambers() {
+ super();
+
+ setMaterial(Material.EMERALD);
+ setLore("Dealing magic damage has &630% &7chance", "of dropping an amber on the ground.", "", "When picked up, ambers stack and",
+ "refund &9{percent}% &7of your missing mana.", "", "&oAmbers can be used in other damaging skills.",
+ "&oThe more you collect, the more powerful the skills.", "", "&e{cooldown}s Cooldown");
+ setPassive();
+
+ addModifier("cooldown", new LinearValue(3, -.1, 1, 3));
+ addModifier("percent", new LinearValue(10, .1, 10, 20));
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ @EventHandler
+ public void a(PlayerAttackEvent event) {
+ PlayerData data = PlayerData.get(event.getData().getUniqueId());
+ if (!event.getAttack().getDamage().hasType(DamageType.SKILL) || !data.getProfess().hasSkill(this))
+ return;
+
+ SkillMetadata cast = data.cast(this);
+ if (!cast.isSuccessful())
+ return;
+
+ Location loc = event.getEntity().getLocation();
+ double a = random.nextDouble() * 2 * Math.PI;
+
+ new Amber(data, loc.add(0, event.getEntity().getHeight() / 2, 0), loc.clone().add(4 * Math.cos(a), 0, 4 * Math.sin(a)), cast.getModifier("percent"));
+ }
+
+ public static class Amber extends BukkitRunnable {
+ private final Location loc;
+ private final PlayerData data;
+ private final double percent;
+
+ private int j;
+
+ private Amber(PlayerData data, Location source, Location loc, double percent) {
+ this.loc = loc;
+ this.data = data;
+ this.percent = percent / 100;
+
+ final Amber amber = this;
+ new ParabolicProjectile(source, loc, Particle.REDSTONE, () -> amber.runTaskTimer(MMOCore.plugin, 0, 3), 1, Color.ORANGE, 1.3f);
+ }
+
+ @Override
+ public void run() {
+ if (!data.isOnline()) return;
+ if (j++ > 66 || !data.getPlayer().getWorld().equals(loc.getWorld())) {
+ cancel();
+ return;
+ }
+
+ if (data.getPlayer().getLocation().distanceSquared(loc) < 2) {
+
+ data.getPlayer().playSound(data.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 1);
+ // data.getSkillData().ambers++;
+ data.giveMana((data.getStats().getStat(StatType.MAX_MANA) - data.getMana()) * percent, PlayerResourceUpdateEvent.UpdateReason.SKILL_REGENERATION);
+
+ cancel();
+ return;
+ }
+
+ for (int j = 0; j < 5; j++)
+ loc.getWorld().spawnParticle(Particle.SPELL_MOB, loc, 0, 1, 0.647, 0, 1);
+ loc.getWorld().spawnParticle(Particle.REDSTONE, loc, 1, new Particle.DustOptions(Color.ORANGE, 1.3f));
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Backstab.java b/src/main/java/net/Indyuce/mmocore/skill/list/Backstab.java
new file mode 100644
index 00000000..e83d0844
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Backstab.java
@@ -0,0 +1,50 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import io.lumine.mythic.lib.damage.DamageType;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.PassiveSkill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.EventHandler;
+
+public class Backstab extends PassiveSkill {
+ public Backstab() {
+ super();
+
+ setMaterial(Material.FLINT);
+ setLore("Backstabs deal &c{extra}%&7 damage.", "", "&9Costs {mana} {mana_name}");
+ setPassive();
+
+ addModifier("cooldown", new LinearValue(0, 0));
+ addModifier("mana", new LinearValue(8, 1));
+ addModifier("extra", new LinearValue(50, 20));
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ @EventHandler
+ public void a(PlayerAttackEvent event) {
+ PlayerData data = PlayerData.get(event.getData().getUniqueId());
+ LivingEntity target = event.getEntity();
+ if (data.isInCombat() || !event.getAttack().getDamage().hasType(DamageType.WEAPON)
+ || event.getPlayer().getEyeLocation().getDirection().angle(target.getEyeLocation().getDirection()) > Math.PI / 6
+ || !data.getProfess().hasSkill(this))
+ return;
+
+ SkillMetadata cast = data.cast(this);
+ if (!cast.isSuccessful())
+ return;
+
+ data.cast(cast.getInfo());
+ event.getAttack().getDamage().multiply(1 + cast.getModifier("extra") / 100, DamageType.PHYSICAL);
+ target.getWorld().spawnParticle(Particle.CRIT, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, .05);
+ target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ENDERMAN_HURT, 1, 1.5f);
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Combo_Attack.java b/src/main/java/net/Indyuce/mmocore/skill/list/Combo_Attack.java
new file mode 100644
index 00000000..e9f363c1
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Combo_Attack.java
@@ -0,0 +1,56 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.damage.DamageType;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class Combo_Attack extends Skill {
+ public Combo_Attack() {
+ super();
+
+ setMaterial(Material.IRON_SWORD);
+ setLore("Violenty slashes your target &8{count}", "times for a total of &8{damage} &7damage.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(20, -.1, 5, 20));
+ addModifier("damage", new LinearValue(9, .3));
+ addModifier("count", new LinearValue(3, .2));
+ addModifier("mana", new LinearValue(10, -.1, 3, 5));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ TargetSkillMetadata cast = new TargetSkillMetadata(caster, skill, 3);
+ if (!cast.isSuccessful())
+ return cast;
+
+ new BukkitRunnable() {
+ final int count = (int) cast.getModifier("count");
+ final double damage = cast.getModifier("damage") / count;
+ final LivingEntity target = cast.getTarget();
+
+ int c;
+
+ @Override
+ public void run() {
+ if (c++ > count || caster.getPlayerData().isOnline()) {
+ cancel();
+ return;
+ }
+
+ target.getWorld().playSound(target.getLocation(), Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, 1, 2);
+ target.getWorld().spawnParticle(Particle.CRIT, target.getLocation().add(0, target.getHeight() / 2, 0), 24, 0, 0, 0, .7);
+ caster.attack(target, damage, DamageType.SKILL, DamageType.PHYSICAL);
+ }
+ }.runTaskTimer(MMOCore.plugin, 0, 5);
+ return cast;
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Control.java b/src/main/java/net/Indyuce/mmocore/skill/list/Control.java
new file mode 100644
index 00000000..6c9ea03e
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Control.java
@@ -0,0 +1,103 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.version.VersionMaterial;
+import io.lumine.mythic.lib.version.VersionSound;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.util.Vector;
+
+public class Control extends Skill {
+ public Control() {
+ super();
+ setMaterial(VersionMaterial.MAGENTA_DYE.toMaterial());
+ setLore("Your target is temporarily slowed for &8{duration} &7seconds.", "As soon as you left click, it gets", "pushed back where you are looking at.", "Knockback force: &f{knockback}%", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(18, -.3, 10, 20));
+ addModifier("mana", new LinearValue(15, 1.5));
+ addModifier("knockback", new LinearValue(30, 3));
+ addModifier("duration", new LinearValue(2, 0));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ TargetSkillMetadata cast = new TargetSkillMetadata(caster, skill, 7);
+ if (!cast.isSuccessful())
+ return cast;
+
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 1);
+ cast.getTarget().addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 0));
+ new TelekinesyRunnable(caster, cast.getTarget(), cast.getModifier("knockback") / 100, cast.getModifier("duration"));
+ return cast;
+ }
+
+ public static class TelekinesyRunnable extends BukkitRunnable implements Listener {
+ private final LivingEntity entity;
+ private final CasterMetadata caster;
+
+ private final double f, d;
+
+ private int j;
+
+ public TelekinesyRunnable(CasterMetadata caster, LivingEntity entity, double force, double duration) {
+ this.entity = entity;
+ this.caster = caster;
+
+ d = duration * 20;
+ f = force;
+
+ runTaskTimer(MMOCore.plugin, 0, 1);
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ @EventHandler
+ public void a(PlayerInteractEvent event) {
+ if (event.getPlayer().equals(caster.getPlayer()) && event.getAction().name().contains("LEFT_CLICK")) {
+ Vector vec = caster.getPlayer().getEyeLocation().getDirection().multiply(3 * f);
+ vec.setY(Math.max(.5, vec.getY() / 2));
+ entity.setVelocity(vec);
+
+ /*
+ * try not to interfere with other potion effects
+ */
+ PotionEffect effect = entity.getPotionEffect(PotionEffectType.SLOW);
+ if (effect.getDuration() < d && effect.getAmplifier() == 0)
+ entity.removePotionEffect(PotionEffectType.SLOW);
+
+ entity.getWorld().spawnParticle(Particle.SPELL_WITCH, entity.getLocation().add(0, entity.getHeight() / 2, 0), 16);
+ entity.getWorld().playSound(entity.getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, 1);
+ close();
+ }
+ }
+
+ @Override
+ public void run() {
+ if (!caster.getPlayerData().isOnline() || entity.isDead() || j++ >= d) {
+ close();
+ return;
+ }
+
+ double a = (double) j / 3;
+ entity.getWorld().spawnParticle(Particle.SPELL_WITCH, entity.getLocation().add(Math.cos(a), entity.getHeight() / 2, Math.sin(a)), 0);
+ }
+
+ private void close() {
+ cancel();
+ HandlerList.unregisterAll(this);
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Deep_Wound.java b/src/main/java/net/Indyuce/mmocore/skill/list/Deep_Wound.java
new file mode 100644
index 00000000..830ad7a2
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Deep_Wound.java
@@ -0,0 +1,47 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.damage.DamageType;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.entity.LivingEntity;
+
+public class Deep_Wound extends Skill {
+ public Deep_Wound() {
+ super();
+ setMaterial(Material.REDSTONE);
+ setLore("You puncture your target, dealing &c{damage} &7damage.", "Damage is increased up to &c+{extra}% &7based",
+ "on your target's missing health.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(20, -.1, 5, 20));
+ addModifier("mana", new LinearValue(8, 3));
+ addModifier("damage", new LinearValue(5, 1.5));
+ addModifier("extra", new LinearValue(50, 20));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ TargetSkillMetadata cast = new TargetSkillMetadata(caster, skill, 3);
+ if (!cast.isSuccessful())
+ return cast;
+
+ LivingEntity target = cast.getTarget();
+ target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 2, 2);
+ target.getWorld().spawnParticle(Particle.CRIT, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, .7);
+ target.getWorld().spawnParticle(Particle.BLOCK_CRACK, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, 2,
+ Material.REDSTONE_BLOCK.createBlockData());
+
+ double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
+ double ratio = (max - target.getHealth()) / max;
+
+ double damage = cast.getModifier("damage") * (1 + cast.getModifier("extra") * ratio / 100);
+ caster.attack(target, damage, DamageType.SKILL, DamageType.PHYSICAL);
+ return cast;
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Empowered_Attack.java b/src/main/java/net/Indyuce/mmocore/skill/list/Empowered_Attack.java
new file mode 100644
index 00000000..fac43136
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Empowered_Attack.java
@@ -0,0 +1,119 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import io.lumine.mythic.lib.damage.DamageType;
+import io.lumine.mythic.lib.version.VersionMaterial;
+import io.lumine.mythic.lib.version.VersionSound;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.util.MMOCoreUtils;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.util.Vector;
+
+public class Empowered_Attack extends Skill {
+ private static final double perb = 5;
+
+ public Empowered_Attack() {
+ super();
+ setMaterial(VersionMaterial.BONE_MEAL.toMaterial());
+ setLore("You charge your weapon with lightning.", "Your next attack deals &f{extra}% &7extra damage", "and spreads to enemies within &f{radius} &7blocks", "for &f{ratio}% &7of the initial damage.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(10, -.2, 5, 10));
+ addModifier("mana", new LinearValue(4, 1));
+ addModifier("radius", new LinearValue(4, 0));
+ addModifier("ratio", new LinearValue(30, 10, 30, 100));
+ addModifier("extra", new LinearValue(30, 8));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ SkillMetadata cast = new SkillMetadata(caster, skill);
+ if (!cast.isSuccessful())
+ return cast;
+
+ caster.getPlayer().playSound(caster.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 1);
+ new EmpoweredAttack(caster, cast.getModifier("extra"), cast.getModifier("ratio"), cast.getModifier("radius"));
+ return cast;
+ }
+
+ private void drawVector(Location loc, Vector vec) {
+
+ double steps = vec.length() * perb;
+ Vector v = vec.clone().normalize().multiply((double) 1 / perb);
+
+ for (int j = 0; j < Math.min(steps, 124); j++)
+ loc.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc.add(v), 0);
+ }
+
+ public class EmpoweredAttack implements Listener {
+ private final CasterMetadata caster;
+ private final double c, r, rad;
+
+ public EmpoweredAttack(CasterMetadata caster, double extra, double ratio, double radius) {
+ this.caster = caster;
+ this.c = 1 + extra / 100;
+ this.r = ratio / 100;
+ this.rad = radius;
+
+ if (caster.getPlayerData().isOnline())
+ new SmallParticleEffect(caster.getPlayer(), Particle.FIREWORKS_SPARK);
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ Bukkit.getScheduler().scheduleSyncDelayedTask(MMOCore.plugin, this::close, 80);
+ }
+
+ private void close() {
+ PlayerAttackEvent.getHandlerList().unregister(this);
+ }
+
+ @EventHandler
+ public void a(PlayerAttackEvent event) {
+ if (!caster.getPlayerData().isOnline()) return;
+ if (event.getPlayer().equals(caster.getPlayer()) && event.getAttack().getDamage().hasType(DamageType.WEAPON)) {
+ close();
+
+ Entity target = event.getEntity();
+
+ /*
+ * play lightning effect
+ */
+ final Location loc = target.getLocation().add(0, target.getHeight() / 2, 0);
+ for (int j = 0; j < 3; j++) {
+ Location clone = loc.clone();
+ double a = random.nextDouble() * Math.PI * 2;
+ loc.add(Math.cos(a), 5, Math.sin(a));
+ drawVector(clone, loc.clone().subtract(clone).toVector());
+ }
+
+ target.getWorld().playSound(target.getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, .5f);
+ target.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, .2);
+
+ double sweep = event.getAttack().getDamage().getDamage() * r;
+ Location src = target.getLocation().add(0, target.getHeight() / 2, 0);
+
+ for (Entity entity : target.getNearbyEntities(rad, rad, rad))
+ if (MMOCoreUtils.canTarget(caster.getPlayerData(), entity)) {
+ drawVector(src, entity.getLocation().add(0, entity.getHeight() / 2, 0).subtract(src).toVector());
+ caster.attack((LivingEntity) entity, sweep, DamageType.PHYSICAL, DamageType.SKILL);
+ }
+
+ /*
+ * Apply damage afterwards otherwise the damage dealt to nearby
+ * entities scale with the extra ability damage.
+ */
+ event.getAttack().getDamage().multiply(1 + c, DamageType.WEAPON);
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Evade.java b/src/main/java/net/Indyuce/mmocore/skill/list/Evade.java
new file mode 100644
index 00000000..13fabe1e
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Evade.java
@@ -0,0 +1,83 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import io.lumine.mythic.lib.damage.DamageType;
+import io.lumine.mythic.lib.version.VersionSound;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class Evade extends Skill {
+ public Evade() {
+ super();
+ setMaterial(Material.LEATHER_BOOTS);
+ setLore("You become imune to damage for &8{duration} &7seconds.", "Cancels when dealing weapon damage.", "", "&e{cooldown}s Cooldown",
+ "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(20, 0));
+ addModifier("mana", new LinearValue(8, 3));
+ addModifier("duration", new LinearValue(2, .3, 2, 10));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ SkillMetadata cast = new SkillMetadata(caster, skill);
+ if (!cast.isSuccessful())
+ return cast;
+
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), VersionSound.ENTITY_ENDERMAN_TELEPORT.toSound(), 1, 2);
+ new SmallParticleEffect(caster.getPlayer(), Particle.CLOUD);
+ new EvadeSkill(caster.getPlayerData(), cast.getModifier("duration"));
+ return cast;
+ }
+
+ private static class EvadeSkill extends BukkitRunnable implements Listener {
+ private final PlayerData data;
+
+ public EvadeSkill(PlayerData data, double duration) {
+ this.data = data;
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ runTaskTimer(MMOCore.plugin, 0, 1);
+ Bukkit.getScheduler().runTaskLater(MMOCore.plugin, this::close, (long) (duration * 20));
+ }
+
+ private void close() {
+ cancel();
+ EntityDamageEvent.getHandlerList().unregister(this);
+ }
+
+ @EventHandler(priority = EventPriority.LOW)
+ public void a(EntityDamageEvent event) {
+ if (!data.isOnline()) return;
+ if (event.getEntity().equals(data.getPlayer()))
+ event.setCancelled(true);
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void b(PlayerAttackEvent event) {
+ if (event.getAttack().getDamage().hasType(DamageType.WEAPON) && !event.isCancelled() && PlayerData.get(event.getData().getUniqueId()).equals(data))
+ close();
+ }
+
+ @Override
+ public void run() {
+ if (!data.isOnline() || data.getPlayer().isDead())
+ close();
+ else
+ data.getPlayer().getWorld().spawnParticle(Particle.CLOUD, data.getPlayer().getLocation().add(0, 1, 0), 0);
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Fire_Berserker.java b/src/main/java/net/Indyuce/mmocore/skill/list/Fire_Berserker.java
new file mode 100644
index 00000000..bd95574f
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Fire_Berserker.java
@@ -0,0 +1,37 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.PassiveSkill;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+
+import java.util.Optional;
+
+public class Fire_Berserker extends PassiveSkill {
+ public Fire_Berserker() {
+ super();
+ setMaterial(Material.FLINT_AND_STEEL);
+ setLore("You deal &c{extra}% &7more damage when on fire.");
+ setPassive();
+
+ addModifier("extra", new LinearValue(10, 5));
+ // addModifier("duration", new LinearValue(10, .1));
+ // addModifier("cooldown", new LinearValue(30, 0));
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void a(PlayerAttackEvent event) {
+ PlayerData data = PlayerData.get(event.getData().getUniqueId());
+ if (event.getPlayer().getFireTicks() > 0) {
+ Optional skill = data.getProfess().findSkill(this);
+ skill.ifPresent(skillInfo -> event.getAttack().getDamage().multiply(1 + skillInfo.getModifier("extra", data.getSkillLevel(this)) / 100));
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Fire_Rage.java b/src/main/java/net/Indyuce/mmocore/skill/list/Fire_Rage.java
new file mode 100644
index 00000000..ca3e5b66
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Fire_Rage.java
@@ -0,0 +1,158 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.MythicLib;
+import io.lumine.mythic.lib.api.player.EquipmentSlot;
+import io.lumine.mythic.lib.api.stat.StatMap;
+import io.lumine.mythic.lib.damage.DamageType;
+import io.lumine.mythic.lib.version.VersionMaterial;
+import io.lumine.mythic.lib.version.VersionSound;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.util.MMOCoreUtils;
+import net.Indyuce.mmocore.api.util.math.VectorRotation;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.util.Vector;
+
+public class Fire_Rage extends Skill {
+ public Fire_Rage() {
+ super();
+ setMaterial(VersionMaterial.FIRE_CHARGE.toMaterial());
+ setLore("For {duration} seconds, you slow down and are able", "to cast up to {count} fireballs by left clicking.", "", "Fireballs deal &c{damage} &7damage upon contact", "and ignite your target for &c{ignite} &7seconds.", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("duration", new LinearValue(8, 0));
+ addModifier("count", new LinearValue(4, 0));
+ addModifier("mana", new LinearValue(15, 1));
+ addModifier("damage", new LinearValue(5, 3));
+ addModifier("ignite", new LinearValue(2, .1));
+ addModifier("cooldown", new LinearValue(9, -.1, 1, 5));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ SkillMetadata cast = new SkillMetadata(caster, skill);
+ if (!cast.isSuccessful())
+ return cast;
+
+ new Rage(caster, cast);
+ return cast;
+ }
+
+ public class Rage extends BukkitRunnable implements Listener {
+ private final CasterMetadata caster;
+ private final StatMap.CachedStatMap cachedStats;
+ private final int count, ignite;
+ private final double damage;
+
+ private int c;
+ private double b;
+ private long last = System.currentTimeMillis();
+
+ /*
+ * time the player needs to wait before firing two fireballs.
+ */
+ private static final long timeOut = 700;
+
+ public Rage(CasterMetadata caster, SkillMetadata cast) {
+ this.caster = caster;
+ this.cachedStats = caster.getPlayerData().getMMOPlayerData().getStatMap().cache(EquipmentSlot.MAIN_HAND);
+ this.ignite = (int) (20 * cast.getModifier("ignite"));
+ this.damage = cast.getModifier("damage");
+ c = count = (int) cast.getModifier("count");
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ Bukkit.getScheduler().runTaskLater(MMOCore.plugin, this::close, (long) (cast.getModifier("duration") * 20));
+ runTaskTimer(MMOCore.plugin, 0, 1);
+ }
+
+ @EventHandler
+ public void a(PlayerInteractEvent event) {
+ if (event.getPlayer().equals(caster.getPlayer()) && event.getAction().name().contains("LEFT_CLICK") && (System.currentTimeMillis() - last) > timeOut) {
+ last = System.currentTimeMillis();
+ castEffect();
+ fireball(c < 2);
+ if (c-- < 2)
+ close();
+ }
+ }
+
+ private void castEffect() {
+ VectorRotation rotation = new VectorRotation(caster.getPlayer().getEyeLocation());
+ for (double a = 0; a < Math.PI * 2; a += Math.PI / 13) {
+ Vector vec = rotation.rotate(new Vector(Math.cos(a), Math.sin(a), 0)).add(caster.getPlayer().getEyeLocation().getDirection().multiply(.5)).multiply(.3);
+ caster.getPlayer().getWorld().spawnParticle(Particle.FLAME, caster.getPlayer().getLocation().add(0, 1.3, 0).add(caster.getPlayer().getEyeLocation().getDirection().multiply(.5)), 0, vec.getX(), vec.getY(), vec.getZ(), .3);
+ }
+ }
+
+ private void close() {
+ if (isCancelled())
+ return;
+
+ cancel();
+ HandlerList.unregisterAll(this);
+ }
+
+ private void fireball(boolean last) {
+ if (last) {
+ caster.getPlayer().removePotionEffect(PotionEffectType.SLOW);
+ caster.getPlayer().removePotionEffect(PotionEffectType.SLOW);
+ }
+
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 1, last ? 0 : 1);
+ new BukkitRunnable() {
+ int j = 0;
+ final Vector vec = caster.getPlayer().getEyeLocation().getDirection();
+ final Location loc = caster.getPlayer().getLocation().add(0, 1.3, 0);
+
+ public void run() {
+ if (j++ > 40)
+ cancel();
+
+ loc.add(vec);
+
+ if (j % 2 == 0)
+ loc.getWorld().playSound(loc, Sound.BLOCK_FIRE_AMBIENT, 2, 1);
+ loc.getWorld().spawnParticle(Particle.FLAME, loc, 4, .1, .1, .1, 0);
+ loc.getWorld().spawnParticle(Particle.LAVA, loc, 0);
+
+ for (Entity target : MMOCoreUtils.getNearbyChunkEntities(loc))
+ if (MythicLib.plugin.getVersion().getWrapper().isInBoundingBox(target, loc) && MMOCoreUtils.canTarget(caster.getPlayerData(), target)) {
+ loc.getWorld().spawnParticle(Particle.LAVA, loc, 8);
+ loc.getWorld().spawnParticle(Particle.FLAME, loc, 32, 0, 0, 0, .1);
+ loc.getWorld().playSound(loc, Sound.ENTITY_BLAZE_HURT, 2, 1);
+ target.setFireTicks(target.getFireTicks() + ignite);
+ caster.attack((LivingEntity) target, damage, DamageType.SKILL, DamageType.PROJECTILE, DamageType.MAGIC);
+ cancel();
+ }
+ }
+ }.runTaskTimer(MMOCore.plugin, 0, 1);
+ }
+
+ @Override
+ public void run() {
+ if (caster.getPlayer().isDead() || !caster.getPlayer().isOnline()) {
+ close();
+ return;
+ }
+
+ b += Math.PI / 30;
+ for (int j = 0; j < c; j++) {
+ double a = Math.PI * 2 * j / count + b;
+ caster.getPlayer().spawnParticle(Particle.FLAME, caster.getPlayer().getLocation().add(Math.cos(a) * 1.5, 1 + Math.sin(a * 1.5) * .7, Math.sin(a) * 1.5), 0);
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Fire_Storm.java b/src/main/java/net/Indyuce/mmocore/skill/list/Fire_Storm.java
similarity index 61%
rename from src/main/java/net/Indyuce/mmocore/skill/Fire_Storm.java
rename to src/main/java/net/Indyuce/mmocore/skill/list/Fire_Storm.java
index 4a704208..000c3c76 100644
--- a/src/main/java/net/Indyuce/mmocore/skill/Fire_Storm.java
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Fire_Storm.java
@@ -1,5 +1,6 @@
-package net.Indyuce.mmocore.skill;
+package net.Indyuce.mmocore.skill.list;
+import net.Indyuce.mmocore.skill.CasterMetadata;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
@@ -10,14 +11,14 @@ import org.bukkit.util.Vector;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
-import net.Indyuce.mmocore.api.skill.SkillResult;
-import net.Indyuce.mmocore.api.skill.result.TargetSkillResult;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.AttackResult;
-import io.lumine.mythic.lib.api.DamageType;
+import io.lumine.mythic.lib.damage.DamageType;;
import io.lumine.mythic.lib.version.VersionSound;
public class Fire_Storm extends Skill {
@@ -33,34 +34,34 @@ public class Fire_Storm extends Skill {
}
@Override
- public SkillResult whenCast(PlayerData data, SkillInfo skill) {
- TargetSkillResult cast = new TargetSkillResult(data, skill, 20);
- if (!cast.isSuccessful() || !data.isOnline())
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ TargetSkillMetadata cast = new TargetSkillMetadata(caster, skill, 20);
+ if (!cast.isSuccessful() )
return cast;
LivingEntity target = cast.getTarget();
- double damage = cast.getModifier("damage");
- int ignite = (int) (20 * cast.getModifier("ignite"));
+ final double damage = cast.getModifier("damage");
+ final int ignite = (int) (20 * cast.getModifier("ignite"));
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 1, 1);
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 1, 1);
new BukkitRunnable() {
int j = 0;
@Override
public void run() {
- if (j++ > 5 || data.getPlayer().isDead() || !data.getPlayer().isOnline() || target.isDead() || !data.getPlayer().getWorld().equals(target.getWorld())) {
+ if (j++ > 5 || caster.getPlayer().isDead() || !caster.getPlayer().isOnline() || target.isDead() || !caster.getPlayer().getWorld().equals(target.getWorld())) {
cancel();
return;
}
// TODO dynamic target location
- data.getPlayer().getWorld().playSound(data.getPlayer().getLocation(), Sound.BLOCK_FIRE_AMBIENT, 1, 1);
- new ParabolicProjectile(data.getPlayer().getLocation().add(0, 1, 0), target.getLocation().add(0, target.getHeight() / 2, 0), randomVector(data.getPlayer()), () -> {
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.BLOCK_FIRE_AMBIENT, 1, 1);
+ new ParabolicProjectile(caster.getPlayer().getLocation().add(0, 1, 0), target.getLocation().add(0, target.getHeight() / 2, 0), randomVector(caster.getPlayer()), () -> {
target.getWorld().playSound(target.getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_TWINKLE.toSound(), 1, 2);
target.getWorld().spawnParticle(Particle.SMOKE_NORMAL, target.getLocation().add(0, target.getHeight() / 2, 0), 8, 0, 0, 0, .15);
- MythicLib.plugin.getDamage().damage(data.getPlayer(), target, new AttackResult(damage, DamageType.SKILL, DamageType.PROJECTILE, DamageType.MAGIC));
+ caster.attack(target, damage, DamageType.SKILL, DamageType.PROJECTILE, DamageType.MAGIC);
target.setFireTicks(ignite);
}, 2, Particle.FLAME);
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Fireball.java b/src/main/java/net/Indyuce/mmocore/skill/list/Fireball.java
new file mode 100644
index 00000000..bf797a17
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Fireball.java
@@ -0,0 +1,104 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.MythicLib;
+import io.lumine.mythic.lib.api.MMORayTraceResult;
+import io.lumine.mythic.lib.damage.DamageType;
+import io.lumine.mythic.lib.version.VersionMaterial;
+import io.lumine.mythic.lib.version.VersionSound;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.util.MMOCoreUtils;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.util.Vector;
+
+public class Fireball extends Skill {
+ public Fireball() {
+ super();
+ setMaterial(VersionMaterial.FIRE_CHARGE.toMaterial());
+ setLore("Casts a deadly fireball onto your", "target, dealing &c{damage} &7damage upon contact", "and igniting it for &c{ignite} &7seconds.", "", "Shatters into 3 blazing hot shards which stick", "to walls and explode 3 seconds later, dealing", "&c{ratio}% &7of the initial spell damage.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("mana", new LinearValue(15, 1));
+ addModifier("damage", new LinearValue(5, 3));
+ addModifier("ignite", new LinearValue(2, .1));
+ addModifier("ratio", new LinearValue(50, 3));
+ addModifier("cooldown", new LinearValue(9, -.1, 1, 5));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ SkillMetadata cast = new SkillMetadata(caster, skill);
+ if (!cast.isSuccessful())
+ return cast;
+
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 1, 1);
+ new BukkitRunnable() {
+ int j = 0;
+ final Vector vec = caster.getPlayer().getEyeLocation().getDirection();
+ final Location loc = caster.getPlayer().getLocation().add(0, 1.3, 0);
+
+ public void run() {
+ if (j++ > 40) {
+ cancel();
+ return;
+ }
+
+ loc.add(vec);
+
+ if (j % 3 == 0)
+ loc.getWorld().playSound(loc, Sound.BLOCK_FIRE_AMBIENT, 2, 1);
+ loc.getWorld().spawnParticle(Particle.FLAME, loc, 4, .02, .02, .02, 0);
+ loc.getWorld().spawnParticle(Particle.LAVA, loc, 0);
+
+ for (Entity target : MMOCoreUtils.getNearbyChunkEntities(loc))
+ if (MythicLib.plugin.getVersion().getWrapper().isInBoundingBox(target, loc) && MMOCoreUtils.canTarget(caster.getPlayerData(), target)) {
+ loc.getWorld().spawnParticle(Particle.LAVA, loc, 8);
+ loc.getWorld().spawnParticle(Particle.FLAME, loc, 32, 0, 0, 0, .1);
+ loc.getWorld().playSound(loc, Sound.ENTITY_BLAZE_HURT, 2, 1);
+ target.setFireTicks((int) (target.getFireTicks() + cast.getModifier("ignite") * 20));
+ double damage = cast.getModifier("damage");
+ caster.attack((LivingEntity) target, damage, DamageType.SKILL, DamageType.PROJECTILE, DamageType.MAGIC);
+
+ new BukkitRunnable() {
+ int i = 0;
+
+ @Override
+ public void run() {
+ if (i++ > 2) {
+ cancel();
+ return;
+ }
+
+ double range = 2.5 * (1 + random.nextDouble());
+ Vector dir = randomDirection();
+ loc.getWorld().playSound(loc, Sound.ENTITY_BLAZE_HURT, 2, 1.5f);
+
+ MMORayTraceResult result = MythicLib.plugin.getVersion().getWrapper().rayTrace(loc, dir, range, entity -> MMOCoreUtils.canTarget(caster.getPlayerData(), entity));
+ if (result.hasHit())
+ caster.attack(result.getHit(), damage, DamageType.SKILL, DamageType.PROJECTILE, DamageType.MAGIC);
+ result.draw(loc.clone(), dir, 8, tick -> tick.getWorld().spawnParticle(Particle.FLAME, tick, 0));
+
+ }
+ }.runTaskTimer(MMOCore.plugin, 3, 3);
+
+ cancel();
+ return;
+ }
+ }
+ }.runTaskTimer(MMOCore.plugin, 0, 1);
+ return cast;
+ }
+
+ private Vector randomDirection() {
+ double x = random.nextDouble() - .5, y = (random.nextDouble() - .2) / 2, z = random.nextDouble() - .5;
+ Vector dir = new Vector(x, y, z);
+ return dir.lengthSquared() == 0 ? new Vector(1, 0, 0) : dir.normalize();
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Furtive_Strike.java b/src/main/java/net/Indyuce/mmocore/skill/list/Furtive_Strike.java
new file mode 100644
index 00000000..9384b224
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Furtive_Strike.java
@@ -0,0 +1,50 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.damage.DamageType;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.LivingEntity;
+
+public class Furtive_Strike extends Skill {
+ public Furtive_Strike() {
+ super();
+ setMaterial(Material.COAL);
+ setLore("Deals &c{damage} &7damage, increased by &c{extra}% &7if", "there are not any enemies within &c{radius} &7blocks.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(20, -.1, 5, 20));
+ addModifier("mana", new LinearValue(8, 3));
+ addModifier("damage", new LinearValue(5, 1.5));
+ addModifier("extra", new LinearValue(50, 20));
+ addModifier("radius", new LinearValue(7, 0));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ TargetSkillMetadata cast = new TargetSkillMetadata(caster, skill, 3);
+ if (!cast.isSuccessful())
+ return cast;
+
+ LivingEntity target = cast.getTarget();
+ target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 2, 1.5f);
+ target.getWorld().spawnParticle(Particle.CRIT, target.getLocation().add(0, target.getHeight() / 2, 0), 32, 0, 0, 0, .5);
+ target.getWorld().spawnParticle(Particle.SMOKE_NORMAL, target.getLocation().add(0, target.getHeight() / 2, 0), 64, 0, 0, 0, .08);
+
+ double damage = cast.getModifier("damage");
+
+ double radius = cast.getModifier("radius");
+ if (target.getNearbyEntities(radius, radius, radius).stream().allMatch(entity -> entity.equals(caster.getPlayer()))) {
+ new SmallParticleEffect(target, Particle.SPELL_WITCH);
+ damage *= 1 + cast.getModifier("extra") / 100;
+ }
+
+ caster.attack(target, damage, DamageType.SKILL, DamageType.PHYSICAL);
+ return cast;
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Greater_Healings.java b/src/main/java/net/Indyuce/mmocore/skill/list/Greater_Healings.java
new file mode 100644
index 00000000..5cb3aa3b
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Greater_Healings.java
@@ -0,0 +1,41 @@
+package net.Indyuce.mmocore.skill.list;
+
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.entity.LivingEntity;
+
+public class Greater_Healings extends Skill {
+ public Greater_Healings() {
+ super();
+ setMaterial(Material.GOLDEN_APPLE);
+ setLore("Instantly grants &a{heal} &7HP to the", "target. Sneak to cast it on yourself.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("mana", new LinearValue(4, 2));
+ addModifier("heal", new LinearValue(10, 4));
+ addModifier("cooldown", new LinearValue(9, -.1, 1, 5));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ SkillMetadata cast = caster.getPlayer().isSneaking() ? new SkillMetadata(caster, skill) : new TargetSkillMetadata(caster, skill, 50, true);
+ if (!cast.isSuccessful())
+ return cast;
+
+ LivingEntity target = cast instanceof TargetSkillMetadata ? ((TargetSkillMetadata) cast).getTarget() : caster.getPlayer();
+
+ double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
+ target.setHealth(Math.min(max, target.getHealth() + cast.getModifier("heal")));
+
+ new SmallParticleEffect(target, Particle.HEART, 1);
+ target.getWorld().playSound(target.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 2, 2);
+ return cast;
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Human_Shield.java b/src/main/java/net/Indyuce/mmocore/skill/list/Human_Shield.java
new file mode 100644
index 00000000..4e06d3ad
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Human_Shield.java
@@ -0,0 +1,105 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.version.VersionMaterial;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class Human_Shield extends Skill {
+ public Human_Shield() {
+ super();
+ setMaterial(VersionMaterial.TOTEM_OF_UNDYING.toMaterial());
+ setLore("Casts a protection charm onto target ally,", "reducing damage taken by &a{reduction}%&7.", "&a{redirect}% &7of this damage is redirected to you.", "Charm is cancelled when reaching &c{low}%&7 health.", "Lasts &a{duration} &7seconds.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(18, -.3, 14, 18));
+ addModifier("mana", new LinearValue(15, 1.5));
+ addModifier("reduction", new LinearValue(30, 3, 30, 70));
+ addModifier("redirect", new LinearValue(30, -2, 20, 30));
+ addModifier("duration", new LinearValue(7, 0));
+ addModifier("low", new LinearValue(10, 0));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ TargetSkillMetadata cast = new TargetSkillMetadata(caster, skill, 7, true);
+ if (!cast.isSuccessful())
+ return cast;
+
+ if (!(cast.getTarget() instanceof Player)) {
+ cast.abort();
+ return cast;
+ }
+
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.ENTITY_BLAZE_AMBIENT, 1, 1);
+ new HumanShield(caster.getPlayerData(), (Player) cast.getTarget(), cast.getModifier("reduction"), cast.getModifier("redirect"), cast.getModifier("duration"), cast.getModifier("low"));
+ return cast;
+ }
+
+ public static class HumanShield extends BukkitRunnable implements Listener {
+ private final PlayerData data;
+ private final Player target;
+ private final double r, rd, d, l;
+
+ private int j;
+
+ public HumanShield(PlayerData data, Player target, double reduction, double redirect, double duration, double low) {
+ this.target = target;
+ this.data = data;
+
+ r = 1 - Math.min(1, reduction / 100);
+ rd = redirect / 100;
+ d = duration * 20;
+ l = low / 100;
+
+ runTaskTimer(MMOCore.plugin, 0, 1);
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ @EventHandler
+ public void a(EntityDamageEvent event) {
+ if (event.getEntity().equals(target)) {
+
+ double damage = event.getDamage() * r;
+ event.setDamage(damage);
+
+ double health = data.getPlayer().getHealth() - damage * rd;
+ if (health > data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue() * l)
+ data.getPlayer().setHealth(health);
+ else {
+ data.getPlayer().setHealth(1);
+ close();
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ if (!data.isOnline() || data.getPlayer().isDead() || !target.isOnline() || target.isDead() || j++ >= d) {
+ close();
+ return;
+ }
+
+ double a = (double) j / 5;
+ target.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, target.getLocation().add(Math.cos(a), 1 + Math.sin(a / 3) / 1.3, Math.sin(a)), 0);
+ }
+
+ private void close() {
+ cancel();
+ HandlerList.unregisterAll(this);
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Ice_Spikes.java b/src/main/java/net/Indyuce/mmocore/skill/list/Ice_Spikes.java
new file mode 100644
index 00000000..3f48f22d
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Ice_Spikes.java
@@ -0,0 +1,79 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.damage.DamageType;
+import io.lumine.mythic.lib.version.VersionMaterial;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.util.MMOCoreUtils;
+import net.Indyuce.mmocore.api.util.math.Line3D;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.LocationSkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.util.Vector;
+
+;
+
+public class Ice_Spikes extends Skill {
+ private static final double radius = 3;
+
+ public Ice_Spikes() {
+ super();
+ setMaterial(VersionMaterial.SNOWBALL.toMaterial());
+ setLore("Ice spikes summon from the ground", "and shatter, each dealing &9{damage} &7damage", "to hit enemies and slowing them down", "for &9{slow} &7seconds.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(6, -.1, 2, 6));
+ addModifier("mana", new LinearValue(20, 2));
+ addModifier("damage", new LinearValue(3, 1));
+ addModifier("slow", new LinearValue(4, 0));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ LocationSkillMetadata cast = new LocationSkillMetadata(caster, skill, 20);
+ if (!cast.isSuccessful())
+ return cast;
+
+ Location loc = cast.getHit();
+ double damage = cast.getModifier("damage");
+ int slow = (int) (20 * cast.getModifier("slow"));
+
+ new BukkitRunnable() {
+ int j = 0;
+
+ @Override
+ public void run() {
+
+ if (j++ > 8) {
+ cancel();
+ return;
+ }
+
+ Location loc1 = loc.clone().add(offset() * radius, 0, offset() * radius).add(0, 2, 0);
+ loc.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc1, 32, 0, 2, 0, 0);
+ loc.getWorld().spawnParticle(Particle.SNOWBALL, loc1, 32, 0, 2, 0, 0);
+ loc.getWorld().playSound(loc1, Sound.BLOCK_GLASS_BREAK, 2, 0);
+
+ Line3D line = new Line3D(loc.toVector(), loc.toVector().add(new Vector(0, 1, 0)));
+ for (Entity entity : MMOCoreUtils.getNearbyChunkEntities(loc1))
+ if (line.distanceSquared(entity.getLocation().toVector()) < radius && Math.abs(entity.getLocation().getY() - loc1.getY()) < 10 && MMOCoreUtils.canTarget(caster.getPlayerData(), entity)) {
+ caster.attack((LivingEntity) entity, damage, DamageType.SKILL, DamageType.MAGIC);
+ ((LivingEntity) entity).addPotionEffect(new PotionEffect(PotionEffectType.SLOW, slow, 0));
+ }
+ }
+ }.runTaskTimer(MMOCore.plugin, 0, 5);
+ return cast;
+ }
+
+ private double offset() {
+ return random.nextDouble() * (random.nextBoolean() ? 1 : -1);
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Minor_Healings.java b/src/main/java/net/Indyuce/mmocore/skill/list/Minor_Healings.java
new file mode 100644
index 00000000..eff1814d
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Minor_Healings.java
@@ -0,0 +1,41 @@
+package net.Indyuce.mmocore.skill.list;
+
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.entity.LivingEntity;
+
+public class Minor_Healings extends Skill {
+ public Minor_Healings() {
+ super();
+ setMaterial(Material.GOLDEN_APPLE);
+ setLore("Instantly grants &a{heal} &7HP to the", "target. Sneak to cast it on yourself.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("mana", new LinearValue(4, 2));
+ addModifier("heal", new LinearValue(4, 2));
+ addModifier("cooldown", new LinearValue(9, -.1, 1, 5));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ SkillMetadata cast = caster.getPlayer().isSneaking() ? new SkillMetadata(caster, skill) : new TargetSkillMetadata(caster, skill, 50, true);
+ if (!cast.isSuccessful())
+ return cast;
+
+ LivingEntity target = cast instanceof TargetSkillMetadata ? ((TargetSkillMetadata) cast).getTarget() : caster.getPlayer();
+
+ double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
+ target.setHealth(Math.min(max, target.getHealth() + cast.getModifier("heal")));
+
+ new SmallParticleEffect(target, Particle.HEART, 1);
+ target.getWorld().playSound(target.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 2, 2);
+ return cast;
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/Neptune_Gift.java b/src/main/java/net/Indyuce/mmocore/skill/list/Neptune_Gift.java
similarity index 87%
rename from src/main/java/net/Indyuce/mmocore/skill/Neptune_Gift.java
rename to src/main/java/net/Indyuce/mmocore/skill/list/Neptune_Gift.java
index e995f95f..0e36614a 100644
--- a/src/main/java/net/Indyuce/mmocore/skill/Neptune_Gift.java
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Neptune_Gift.java
@@ -1,7 +1,8 @@
-package net.Indyuce.mmocore.skill;
+package net.Indyuce.mmocore.skill.list;
import java.util.Optional;
+import net.Indyuce.mmocore.skill.PassiveSkill;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
@@ -10,11 +11,11 @@ import org.bukkit.event.Listener;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.skill.Skill;
+import net.Indyuce.mmocore.skill.Skill;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import io.lumine.mythic.lib.version.VersionMaterial;
-public class Neptune_Gift extends Skill implements Listener {
+public class Neptune_Gift extends PassiveSkill {
public Neptune_Gift() {
super("NEPTUNE_GIFT");
setName("Neptune's Gift");
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Power_Mark.java b/src/main/java/net/Indyuce/mmocore/skill/list/Power_Mark.java
new file mode 100644
index 00000000..ec235df6
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Power_Mark.java
@@ -0,0 +1,134 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import io.lumine.mythic.lib.damage.DamageType;
+import io.lumine.mythic.lib.version.VersionMaterial;
+import io.lumine.mythic.lib.version.VersionSound;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.util.MMOCoreUtils;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.PassiveSkill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.*;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.util.Vector;
+
+;
+
+public class Power_Mark extends PassiveSkill {
+ public Power_Mark() {
+ super();
+ setMaterial(VersionMaterial.WITHER_SKELETON_SKULL.toMaterial());
+ setLore("Attacking an enemy applies a deadly", "magical mark which spreads accross the", "ground. This mark accumulates &6{ratio}%", "of the damage dealt to the initial", "target over &6{duration} &7seconds.", "", "After this duration, the mark bursts, dealing", "accumulated damage to nearby enemies and", "stunning them for &6{stun}+ &7seconds.", "", "The more damage, the longer the stun.", "", "&e{cooldown}s Cooldown");
+ setPassive();
+
+ addModifier("stun", new LinearValue(.4, .03));
+ addModifier("ratio", new LinearValue(10, 5));
+ addModifier("duration", new LinearValue(10, .1));
+ addModifier("cooldown", new LinearValue(30, 0));
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ @EventHandler
+ public void a(PlayerAttackEvent event) {
+ PlayerData data = PlayerData.get(event.getData().getUniqueId());
+ if (!event.getAttack().getDamage().hasType(DamageType.WEAPON) || !data.getProfess().hasSkill(this))
+ return;
+
+ SkillMetadata cast = data.cast(this);
+ if (!cast.isSuccessful())
+ return;
+
+ new PowerMark(new CasterMetadata(data), cast, event.getEntity().getLocation());
+ }
+
+ public class PowerMark extends BukkitRunnable implements Listener {
+ private final CasterMetadata caster;
+ private final Location loc;
+
+ private final double duration;
+ private final double ratio;
+ private double stun;
+
+ private double accumulate;
+ private int j;
+
+ public PowerMark(CasterMetadata caster, SkillMetadata cast, Location loc) {
+ this.caster = caster;
+ this.loc = loc;
+
+ loc.getWorld().playSound(loc, Sound.BLOCK_END_PORTAL_FRAME_FILL, 2, 1);
+
+ duration = cast.getModifier("duration");
+ ratio = cast.getModifier("ratio") / 100;
+ stun = cast.getModifier("stun");
+
+ runTaskTimer(MMOCore.plugin, 0, 1);
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ private void unregister() {
+ PlayerAttackEvent.getHandlerList().unregister(this);
+ cancel();
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void stackDamage(PlayerAttackEvent event) {
+ if (!event.isCancelled() && j < 20 * (duration - 2) && radiusCheck(event.getEntity().getLocation()) && event.getPlayer().equals(caster.getPlayer())) {
+ accumulate += event.getAttack().getDamage().getDamage() * ratio;
+ new ParabolicProjectile(event.getEntity().getLocation().add(0, event.getEntity().getHeight() / 2, 0), loc, () -> loc.getWorld().playSound(loc, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1), Color.PURPLE);
+ }
+ }
+
+ private boolean radiusCheck(Location loc) {
+ return loc.getWorld().equals(this.loc.getWorld()) && loc.distanceSquared(this.loc) < 16;
+ }
+
+ @Override
+ public void run() {
+ if (j++ > duration * 20) {
+ unregister();
+
+ for (double a = 0; a < Math.PI * 2; a += Math.PI * 2 / 17)
+ new ParabolicProjectile(loc, loc.clone().add(6 * Math.cos(a), 0, 6 * Math.sin(a)), Particle.SPELL_WITCH);
+
+ loc.getWorld().playSound(loc, Sound.ENTITY_GENERIC_EXPLODE, 2, 0);
+ loc.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, loc.clone().add(0, 1, 0), 16, 2, 2, 2, 0);
+ loc.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, loc.clone().add(0, 1, 0), 24, 0, 0, 0, .3f);
+
+ stun += Math.log(Math.max(1, accumulate - 10)) / 8;
+
+ for (Entity entity : MMOCoreUtils.getNearbyChunkEntities(loc))
+ if (entity.getLocation().distanceSquared(loc) < 25 && MMOCoreUtils.canTarget(caster.getPlayerData(), entity)) {
+ ((LivingEntity) entity).addPotionEffect(new PotionEffect(PotionEffectType.SLOW, (int) (stun * 20), 10, false, false));
+ caster.attack((LivingEntity) entity, accumulate, DamageType.SKILL, DamageType.MAGIC);
+ entity.setVelocity(format(entity.getLocation().subtract(loc).toVector().setY(0)).setY(.3));
+ }
+ return;
+ }
+
+ if (j % 2 == 0 && j > 20 * (duration - 2))
+ loc.getWorld().playSound(loc, VersionSound.BLOCK_NOTE_BLOCK_PLING.toSound(), 1, (float) (1 + (j - 20 * (duration - 2)) / 40));
+
+ double a = (double) j / 16;
+ double r = Math.sqrt(Math.min(duration * 2 - (double) j / 10, 4)) * 2;
+ for (double k = 0; k < Math.PI * 2; k += Math.PI * 2 / 5)
+ loc.getWorld().spawnParticle(Particle.SPELL_WITCH, loc.clone().add(r * Math.cos(k + a), 0, r * Math.sin(k + a)), 0);
+ }
+ }
+
+ private Vector format(Vector vec) {
+ return vec.length() < .01 ? new Vector(0, 0, 0) : vec.normalize();
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Sneaky_Picky.java b/src/main/java/net/Indyuce/mmocore/skill/list/Sneaky_Picky.java
new file mode 100644
index 00000000..96b33915
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Sneaky_Picky.java
@@ -0,0 +1,48 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
+import io.lumine.mythic.lib.damage.DamageType;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.skill.PassiveSkill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.EventHandler;
+
+public class Sneaky_Picky extends PassiveSkill {
+ public Sneaky_Picky() {
+ super();
+ setMaterial(Material.DIAMOND_SWORD);
+ setLore("Your attack is empowered by &f{extra}% &7when", "delivering the first blow during a fight.", "", "&9Costs {mana} {mana_name}");
+ setPassive();
+
+ addModifier("cooldown", new LinearValue(0, 0));
+ addModifier("mana", new LinearValue(8, 1));
+ addModifier("extra", new LinearValue(50, 20));
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ @EventHandler
+ public void a(PlayerAttackEvent event) {
+ PlayerData data = PlayerData.get(event.getData().getUniqueId());
+ if (!event.getAttack().getDamage().hasType(DamageType.WEAPON) || data.isInCombat() || !data.getProfess().hasSkill(this))
+ return;
+
+ SkillMetadata cast = data.cast(this);
+ if (!cast.isSuccessful())
+ return;
+
+ data.cast(cast.getInfo());
+
+ event.getAttack().getDamage().multiply(1 + cast.getModifier("extra") / 100, DamageType.WEAPON);
+ LivingEntity target = event.getEntity();
+ target.getWorld().spawnParticle(Particle.SMOKE_NORMAL, target.getLocation().add(0, target.getHeight() / 2, 0), 64, 0, 0, 0, .05);
+ target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 1, 2);
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Telekinesy.java b/src/main/java/net/Indyuce/mmocore/skill/list/Telekinesy.java
new file mode 100644
index 00000000..e88933c4
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Telekinesy.java
@@ -0,0 +1,98 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.version.VersionMaterial;
+import io.lumine.mythic.lib.version.VersionSound;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.entity.Entity;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class Telekinesy extends Skill {
+ public Telekinesy() {
+ super();
+ setMaterial(VersionMaterial.MAGENTA_DYE.toMaterial());
+ setLore("You take the control over your target", "for &9{duration} &7seconds. Left click to throw him.", "Knockback force: &f{knockback}%", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(20, -.3, 10, 20));
+ addModifier("mana", new LinearValue(20, 2));
+ addModifier("knockback", new LinearValue(50, 10));
+ addModifier("duration", new LinearValue(3, .1, 3, 6));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ TargetSkillMetadata cast = new TargetSkillMetadata(caster, skill, 7);
+ if (!cast.isSuccessful())
+ return cast;
+
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 1);
+ new TelekinesyRunnable(caster.getPlayerData(), cast.getTarget(), cast.getModifier("duration"), cast.getModifier("knockback") / 100);
+ return cast;
+ }
+
+ public static class TelekinesyRunnable extends BukkitRunnable implements Listener {
+ private final Entity entity;
+ private final PlayerData data;
+
+ private final long duration;
+ private final double d, f;
+
+ private int j;
+
+ public TelekinesyRunnable(PlayerData data, Entity entity, double duration, double force) {
+ this.entity = entity;
+ this.data = data;
+
+ d = data.getPlayer().getLocation().distance(entity.getLocation());
+ f = force;
+ this.duration = (long) (20 * duration);
+
+ runTaskTimer(MMOCore.plugin, 0, 1);
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ }
+
+ @EventHandler
+ public void a(PlayerInteractEvent event) {
+ if (event.getPlayer().equals(data.getPlayer()) && event.getAction().name().contains("LEFT_CLICK")) {
+ entity.setVelocity(data.getPlayer().getEyeLocation().getDirection().multiply(1.5 * f));
+ entity.getWorld().playSound(entity.getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, 1);
+ entity.getWorld().spawnParticle(Particle.SPELL_WITCH, entity.getLocation().add(0, entity.getHeight() / 2, 0), 16);
+ close();
+ }
+ }
+
+ @Override
+ public void run() {
+ if (!data.isOnline() || entity.isDead() || j++ >= duration) {
+ close();
+ return;
+ }
+
+ if (j % 8 == 0)
+ new ParabolicProjectile(data.getPlayer().getEyeLocation(), entity.getLocation().add(0, entity.getHeight() / 2, 0), Particle.SPELL_WITCH);
+
+ Location loc = data.getPlayer().getEyeLocation().add(data.getPlayer().getEyeLocation().getDirection().multiply(d));
+ entity.setVelocity(loc.subtract(entity.getLocation().add(0, entity.getHeight() / 2, 0)).toVector().multiply(2));
+ entity.setFallDistance(0);
+ }
+
+ private void close() {
+ cancel();
+ HandlerList.unregisterAll(this);
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Warp.java b/src/main/java/net/Indyuce/mmocore/skill/list/Warp.java
new file mode 100644
index 00000000..fda98891
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Warp.java
@@ -0,0 +1,59 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.version.VersionSound;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+
+public class Warp extends Skill {
+ public Warp() {
+ super();
+ setMaterial(Material.ENDER_PEARL);
+ setLore("Teleports you to target location.", "Max. Range: &5{range}", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(15, -.3, 2, 15));
+ addModifier("mana", new LinearValue(8, 3));
+ addModifier("range", new LinearValue(16, 1, 0, 100));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ WarpSkillMetadata cast = new WarpSkillMetadata(caster, skill);
+ if (!cast.isSuccessful())
+ return cast;
+
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1, 2);
+
+ Location loc = cast.block.getLocation().add(0, 1, 0);
+ loc.setYaw(caster.getPlayer().getLocation().getYaw());
+ loc.setPitch(caster.getPlayer().getLocation().getPitch());
+
+ new ParabolicProjectile(caster.getPlayer().getLocation().add(0, 1, 0), loc.clone().add(0, 1, 0), () -> {
+ if (caster.getPlayer().isOnline() && !caster.getPlayer().isDead()) {
+ caster.getPlayer().teleport(loc);
+ caster.getPlayer().getWorld().spawnParticle(Particle.EXPLOSION_LARGE, caster.getPlayer().getLocation().add(0, 1, 0), 0);
+ caster.getPlayer().getWorld().spawnParticle(Particle.SPELL_INSTANT, caster.getPlayer().getLocation().add(0, 1, 0), 32, 0, 0, 0, .1);
+ caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), VersionSound.ENTITY_ENDERMAN_TELEPORT.toSound(), 1, 1);
+ }
+ }, 2, Particle.SPELL_INSTANT);
+ return cast;
+ }
+
+ private class WarpSkillMetadata extends SkillMetadata {
+ private Block block;
+
+ public WarpSkillMetadata(CasterMetadata caster, SkillInfo skill) {
+ super(caster, skill);
+
+ if (isSuccessful() && (block = caster.getPlayer().getTargetBlock(null, (int) getModifier("range"))) == null)
+ abort();
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/list/Weaken.java b/src/main/java/net/Indyuce/mmocore/skill/list/Weaken.java
new file mode 100644
index 00000000..95688765
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/list/Weaken.java
@@ -0,0 +1,76 @@
+package net.Indyuce.mmocore.skill.list;
+
+import io.lumine.mythic.lib.version.VersionMaterial;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
+import net.Indyuce.mmocore.api.util.math.particle.ParabolicProjectile;
+import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.metadata.SkillMetadata;
+import net.Indyuce.mmocore.skill.metadata.TargetSkillMetadata;
+import org.bukkit.Bukkit;
+import org.bukkit.Particle;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.util.Vector;
+
+public class Weaken extends Skill {
+ public Weaken() {
+ super();
+ setMaterial(VersionMaterial.MAGENTA_DYE.toMaterial());
+ setLore("The target is weakened for", "&8{duration} &7seconds and is dealt", "&7extra &8{ratio}% &7damage.", "", "&e{cooldown}s Cooldown", "&9Costs {mana} {mana_name}");
+
+ addModifier("cooldown", new LinearValue(20, -.1, 5, 20));
+ addModifier("mana", new LinearValue(4, 1));
+ addModifier("ratio", new LinearValue(30, 3));
+ addModifier("duration", new LinearValue(10, -.1, 5, 10));
+ }
+
+ @Override
+ public SkillMetadata whenCast(CasterMetadata caster, SkillInfo skill) {
+ TargetSkillMetadata cast = new TargetSkillMetadata(caster, skill, 7);
+ if (!cast.isSuccessful())
+ return cast;
+
+ LivingEntity target = cast.getTarget();
+ new ParabolicProjectile(caster.getPlayer().getLocation().add(0, 1, 0), target.getLocation().add(0, target.getHeight() / 2, 0), randomVector(caster.getPlayer()), () -> {
+ if (!target.isDead())
+ new Weakened(target, cast.getModifier("ratio"), cast.getModifier("duration"));
+ }, 2, Particle.SPELL_WITCH);
+ return cast;
+ }
+
+ private Vector randomVector(Player player) {
+ double a = Math.toRadians(player.getEyeLocation().getYaw() + 90);
+ a += (random.nextBoolean() ? 1 : -1) * (random.nextDouble() + .5) * Math.PI / 6;
+ return new Vector(Math.cos(a), .8, Math.sin(a)).normalize().multiply(.4);
+ }
+
+ public static class Weakened implements Listener {
+ private final Entity entity;
+ private final double c;
+
+ public Weakened(Entity entity, double ratio, double duration) {
+ this.entity = entity;
+ this.c = 1 + ratio / 100;
+
+ new SmallParticleEffect(entity, Particle.SPELL_WITCH);
+
+ Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
+ Bukkit.getScheduler().scheduleSyncDelayedTask(MMOCore.plugin, () -> EntityDamageByEntityEvent.getHandlerList().unregister(this), (int) duration * 20);
+ }
+
+ @EventHandler
+ public void a(EntityDamageByEntityEvent event) {
+ if (event.getEntity().equals(entity)) {
+ event.getEntity().getWorld().spawnParticle(Particle.SPELL_WITCH, entity.getLocation().add(0, entity.getHeight() / 2, 0), 16, .5, .5, .5, 0);
+ event.setDamage(event.getDamage() * c);
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/metadata/LocationSkillMetadata.java b/src/main/java/net/Indyuce/mmocore/skill/metadata/LocationSkillMetadata.java
new file mode 100644
index 00000000..d88cdeb1
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/metadata/LocationSkillMetadata.java
@@ -0,0 +1,51 @@
+package net.Indyuce.mmocore.skill.metadata;
+
+import net.Indyuce.mmocore.api.util.MMOCoreUtils;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
+import org.bukkit.FluidCollisionMode;
+import org.bukkit.Location;
+import org.bukkit.util.RayTraceResult;
+
+public class LocationSkillMetadata extends SkillMetadata {
+ private Location loc;
+
+ /**
+ * @param caster Player casting the skill
+ * @param skill Skill being cast
+ * @param range Skill raycast range
+ */
+ public LocationSkillMetadata(CasterMetadata caster, SkillInfo skill, double range) {
+ this(caster, skill, range, false);
+ }
+
+ /**
+ * @param caster Player casting the skill
+ * @param skill Skill being cast
+ * @param range Skill raycast range
+ * @param buff If the skill is a buff ie if it can be cast on party members
+ */
+ public LocationSkillMetadata(CasterMetadata caster, SkillInfo skill, double range, boolean buff) {
+ super(caster, skill);
+
+ if (isSuccessful()) {
+
+ RayTraceResult result = caster.getPlayer().getWorld().rayTrace(caster.getPlayer().getEyeLocation(),
+ caster.getPlayer().getEyeLocation().getDirection(), range, FluidCollisionMode.ALWAYS, true, 1.0D,
+ entity -> MMOCoreUtils.canTarget(caster.getPlayerData(), entity, buff));
+ if (result == null)
+ abort(CancelReason.OTHER);
+ else
+ loc = result.getHitBlock() != null ? result.getHitBlock().getLocation()
+ : result.getHitEntity() != null ? result.getHitEntity().getLocation() : null;
+ }
+ }
+
+ public boolean hasHit() {
+ return loc != null;
+ }
+
+ public Location getHit() {
+ return loc;
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/metadata/SkillMetadata.java b/src/main/java/net/Indyuce/mmocore/skill/metadata/SkillMetadata.java
new file mode 100644
index 00000000..31607ff7
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/metadata/SkillMetadata.java
@@ -0,0 +1,123 @@
+package net.Indyuce.mmocore.skill.metadata;
+
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.comp.flags.FlagPlugin.CustomFlag;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
+
+import java.util.Objects;
+
+public class SkillMetadata {
+ private final SkillInfo skill;
+ private final int level;
+ private final double mana, cooldown, stamina;
+
+ private CancelReason cancelReason;
+
+ public SkillMetadata(CasterMetadata caster, SkillInfo skill) {
+ this.skill = skill;
+
+ PlayerData data = caster.getPlayerData();
+
+ level = data.getSkillLevel(skill.getSkill());
+ cooldown = (skill.getSkill().hasModifier("cooldown") ? data.getSkillData().getCooldown(skill) : 0);
+ mana = (skill.getSkill().hasModifier("mana") ? skill.getModifier("mana", level) : 0);
+ stamina = (skill.getSkill().hasModifier("stamina") ? skill.getModifier("stamina", level) : 0);
+ cancelReason = !data.hasSkillUnlocked(skill) ? CancelReason.LOCKED
+ : cooldown > 0 ? CancelReason.COOLDOWN
+ : mana > data.getMana() ? CancelReason.MANA
+ : stamina > data.getStamina() ? CancelReason.STAMINA
+ : !data.isOnline() ? CancelReason.OTHER
+ : !MMOCore.plugin.flagPlugin.isFlagAllowed(data.getPlayer(), CustomFlag.SKILLS) ? CancelReason.FLAG
+ : null;
+ }
+
+ public SkillMetadata(PlayerData data, SkillInfo skill, CancelReason reason) {
+ this.skill = skill;
+ this.cancelReason = reason;
+
+ level = data.getSkillLevel(skill.getSkill());
+ cooldown = skill.getSkill().hasModifier("cooldown") ? data.getSkillData().getCooldown(skill) : 0;
+ mana = skill.getSkill().hasModifier("mana") ? skill.getModifier("mana", level) : 0;
+ stamina = (skill.getSkill().hasModifier("stamina") ? skill.getModifier("stamina", level) : 0);
+ }
+
+ public Skill getSkill() {
+ return skill.getSkill();
+ }
+
+ public SkillInfo getInfo() {
+ return skill;
+ }
+
+ public int getLevel() {
+ return level;
+ }
+
+ public double getStaminaCost() {
+ return stamina;
+ }
+
+ public double getManaCost() {
+ return mana;
+ }
+
+ public double getCooldown() {
+ return cooldown;
+ }
+
+ public boolean isSuccessful() {
+ return cancelReason == null;
+ }
+
+ public CancelReason getCancelReason() {
+ return cancelReason;
+ }
+
+ public void abort() {
+ abort(CancelReason.OTHER);
+ }
+
+ public void abort(CancelReason reason) {
+ cancelReason = Objects.requireNonNull(reason, "Reason cannot be null");
+ }
+
+ public double getModifier(String modifier) {
+ return skill.getModifier(modifier, level);
+ }
+
+ public enum CancelReason {
+
+ /**
+ * Flag plugin like WorldGuard or any other
+ */
+ FLAG,
+
+ /**
+ * Not enough stamina
+ */
+ MANA,
+
+ /**
+ * Not enough mana
+ */
+ STAMINA,
+
+ /**
+ * Skill still on cooldown
+ */
+ COOLDOWN,
+
+ /**
+ * Skill is locked
+ */
+ LOCKED,
+
+ /**
+ * Anything else
+ */
+ OTHER;
+ }
+}
diff --git a/src/main/java/net/Indyuce/mmocore/skill/metadata/TargetSkillMetadata.java b/src/main/java/net/Indyuce/mmocore/skill/metadata/TargetSkillMetadata.java
new file mode 100644
index 00000000..134e2917
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmocore/skill/metadata/TargetSkillMetadata.java
@@ -0,0 +1,43 @@
+package net.Indyuce.mmocore.skill.metadata;
+
+import io.lumine.mythic.lib.MythicLib;
+import io.lumine.mythic.lib.api.MMORayTraceResult;
+import net.Indyuce.mmocore.api.util.MMOCoreUtils;
+import net.Indyuce.mmocore.skill.CasterMetadata;
+import net.Indyuce.mmocore.skill.Skill.SkillInfo;
+import org.bukkit.entity.LivingEntity;
+
+public class TargetSkillMetadata extends SkillMetadata {
+ private LivingEntity target;
+
+ /**
+ * @param caster Player casting the skill
+ * @param skill Skill being cast
+ * @param range Skill raycast range
+ */
+ public TargetSkillMetadata(CasterMetadata caster, SkillInfo skill, double range) {
+ this(caster, skill, range, false);
+ }
+
+ /**
+ * @param caster Player casting the skill
+ * @param skill Skill being cast
+ * @param range Skill raycast range
+ * @param buff If the skill is a buff ie if it can be cast on party members
+ */
+ public TargetSkillMetadata(CasterMetadata caster, SkillInfo skill, double range, boolean buff) {
+ super(caster, skill);
+
+ if (isSuccessful()) {
+ MMORayTraceResult result = MythicLib.plugin.getVersion().getWrapper().rayTrace(caster.getPlayer(), range, entity -> MMOCoreUtils.canTarget(caster.getPlayerData(), entity, buff));
+ if (!result.hasHit())
+ abort();
+ else
+ target = result.getHit();
+ }
+ }
+
+ public LivingEntity getTarget() {
+ return target;
+ }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 02b54056..2f33ef1c 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -45,14 +45,14 @@ default-playerdata:
# The list of all conditions which must be met for the
# BLOCK REGEN and BLOCK RESTRICTIONS to apply. Set to
# 'custom-mine-conditions: []' to disable custom mining entirely.
-custom-mine-conditions:
-- 'world{name="world,world_nether,world_the_end"}'
-- 'region{name="example_region,example_region2,__global__"}'
#
# custom-mine-conditions:
# - 'world{name="__global__"}'
#
# ^ will enable custom mining server wide
+custom-mine-conditions:
+ - 'world{name="world,world_nether,world_the_end"}'
+ - 'region{name="example_region,example_region2,__global__"}'
# Set to true to prevent vanilla blocks from being
# broken when custom mining conditions are met
@@ -121,14 +121,17 @@ vanilla-exp-redirection:
# Requires a SERVER reload when changed.
override-vanilla-exp: true
+# Check the target player's RPG profile when shift when shift right clicking.
+shift-click-player-profile-check: true
+
# If main class experience holograms should be displayed
# whenever a player earns main class exp
-display-main-class-exp-holograms: true
+display-main-class-exp-holograms: true
# Requires a SERVER reload when changed.
death-exp-loss:
enabled: false
-
+
# Percentage of current EXP you lose when dying.
percent: 30