Improved implementation of elemental and projectile attacks to match new ML tools

This commit is contained in:
Jules 2022-02-08 21:24:38 +01:00
parent 3ba7839833
commit 4cc82848bd
7 changed files with 140 additions and 174 deletions

View File

@ -4,10 +4,12 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.comp.target.InteractionType;
import io.lumine.mythic.lib.damage.DamageMetadata;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.version.VersionMaterial;
import io.lumine.mythic.lib.version.VersionSound;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.listener.ElementListener;
import org.bukkit.*;
import org.bukkit.entity.Entity;
@ -20,15 +22,14 @@ import org.bukkit.util.Consumer;
import org.bukkit.util.Vector;
public enum Element {
FIRE(Material.BLAZE_POWDER, ChatColor.DARK_RED, new ElementParticle(Particle.FLAME, .05f, 8), (attack, target, damage, absolute) -> {
FIRE(Material.BLAZE_POWDER, ChatColor.DARK_RED, new ElementParticle(Particle.FLAME, .05f, 8), (attacker, target, relative, absolute) -> {
target.getWorld().spawnParticle(Particle.LAVA, target.getLocation().add(0, target.getHeight() / 2, 0), 14);
target.getWorld().playSound(target.getLocation(), Sound.ENTITY_BLAZE_HURT, 2, .8f);
target.setFireTicks((int) (damage * 2));
attack.getDamage().add(absolute);
target.setFireTicks((int) (relative * 2));
}, 19, 25),
ICE(VersionMaterial.SNOWBALL.toMaterial(), ChatColor.AQUA, new ElementParticle(Particle.BLOCK_CRACK, .07f, 16, Material.ICE),
(attack, target, damage, absolute) -> {
(attacker, target, relative, absolute) -> {
new BukkitRunnable() {
double y = 0;
final Location loc = target.getLocation();
@ -44,52 +45,48 @@ public enum Element {
}
}.runTaskTimer(MMOItems.plugin, 0, 1);
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_GLASS_BREAK, 2, 0);
target.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, (int) (damage * 1.5), 5));
attack.getDamage().add(absolute);
target.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, (int) (relative * 1.5), 5));
}, 20, 24),
WIND(Material.FEATHER, ChatColor.GRAY, new ElementParticle(Particle.EXPLOSION_NORMAL, .06f, 8), (attack, target, damage, absolute) -> {
WIND(Material.FEATHER, ChatColor.GRAY, new ElementParticle(Particle.EXPLOSION_NORMAL, .06f, 8), (attacker, target, relative, absolute) -> {
target.getWorld().playSound(target.getLocation(), VersionSound.ENTITY_ENDER_DRAGON_GROWL.toSound(), 2, 2f);
Vector vec = target.getLocation().subtract(attack.getPlayer().getLocation()).toVector().normalize().multiply(1.7).setY(.5);
Vector vec = target.getLocation().subtract(attacker.getPlayer().getLocation()).toVector().normalize().multiply(1.7).setY(.5);
target.setVelocity(vec);
for (Entity entity : target.getNearbyEntities(3, 1, 3))
if (MMOUtils.canTarget(attack.getPlayer(), entity, InteractionType.OFFENSE_ACTION)) {
if (MMOUtils.canTarget(attacker.getPlayer(), entity, InteractionType.OFFENSE_ACTION)) {
entity.playEffect(EntityEffect.HURT);
entity.setVelocity(vec);
}
attack.getDamage().add(absolute);
for (double k = 0; k < Math.PI * 2; k += Math.PI / 16)
target.getWorld().spawnParticle(Particle.CLOUD, target.getLocation().add(0, target.getHeight() / 2, 0), 0, Math.cos(k), .01,
Math.sin(k), .15);
}, 28, 34),
EARTH(VersionMaterial.OAK_SAPLING.toMaterial(), ChatColor.GREEN, new ElementParticle(Particle.BLOCK_CRACK, .05f, 24, Material.DIRT),
(attack, target, damage, absolute) -> {
(attacker, target, relative, absolute) -> {
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_GRASS_BREAK, 2, 0);
target.getWorld().spawnParticle(Particle.BLOCK_CRACK, target.getLocation().add(0, .1, 0), 64, 1, 0, 1,
Material.DIRT.createBlockData());
attack.getDamage().add(absolute);
target.setVelocity(new Vector(0, 1, 0));
for (Entity entity : target.getNearbyEntities(3, 1, 3))
if (MMOUtils.canTarget(attack.getPlayer(), entity, InteractionType.OFFENSE_ACTION))
if (MMOUtils.canTarget(attacker.getPlayer(), entity, InteractionType.OFFENSE_ACTION))
entity.setVelocity(new Vector(0, 1, 0));
}, 29, 33),
THUNDER(VersionMaterial.GUNPOWDER.toMaterial(), ChatColor.YELLOW, new ElementParticle(Particle.FIREWORKS_SPARK, .05f, 8), (attack, target, damage, absolute) -> {
THUNDER(VersionMaterial.GUNPOWDER.toMaterial(), ChatColor.YELLOW, new ElementParticle(Particle.FIREWORKS_SPARK, .05f, 8), (attacker, target, relative, absolute) -> {
target.getWorld().playSound(target.getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_LARGE_BLAST.toSound(), 2, 0);
for (Entity entity : target.getNearbyEntities(3, 2, 3))
if (MMOUtils.canTarget(attack.getPlayer(), entity, InteractionType.OFFENSE_ACTION))
MythicLib.plugin.getDamage().damage(new ItemAttackMetadata(new DamageMetadata(attack.getDamage().getDamage() * damage / 100, DamageType.WEAPON), attack), (LivingEntity) entity);
if (MMOUtils.canTarget(attacker.getPlayer(), entity, InteractionType.OFFENSE_ACTION))
MythicLib.plugin.getDamage().damage(new ItemAttackMetadata(new DamageMetadata(absolute, DamageType.WEAPON), attacker), (LivingEntity) entity);
attack.getDamage().add(absolute);
for (double k = 0; k < Math.PI * 2; k += Math.PI / 16)
target.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, target.getLocation().add(0, target.getHeight() / 2, 0), 0, Math.cos(k), .01,
Math.sin(k), .18);
}, 30, 32),
WATER(VersionMaterial.LILY_PAD.toMaterial(), ChatColor.BLUE, new ElementParticle(Particle.BLOCK_CRACK, .07f, 32, Material.WATER),
(attack, target, damage, absolute) -> {
(attacker, target, damage, absolute) -> {
ElementListener.weaken(target);
new BukkitRunnable() {
double step = Math.PI / 2;
@ -107,11 +104,11 @@ public enum Element {
}, 37, 43),
LIGHTNESS(Material.GLOWSTONE_DUST, ChatColor.WHITE, new ElementParticle(Particle.BLOCK_CRACK, .07f, 32, Material.WHITE_WOOL),
(attack, target, damage, absolute) -> {
(attacker, target, relative, absolute) -> {
// TODO
}, 38, 42),
DARKNESS(Material.COAL, ChatColor.DARK_GRAY, new ElementParticle(Particle.BLOCK_CRACK, .07f, 32, Material.COAL_BLOCK), (attack, target, damage, absolute) -> {
DARKNESS(Material.COAL, ChatColor.DARK_GRAY, new ElementParticle(Particle.BLOCK_CRACK, .07f, 32, Material.COAL_BLOCK), (attacker, target, relative, absolute) -> {
// TODO
}, 39, 41),
@ -163,9 +160,17 @@ public enum Element {
return defenseGuiSlot;
}
public interface ElementHandler {
void elementAttack(ItemAttackMetadata attack, LivingEntity target, double damage, double absolute);
}
@FunctionalInterface
public interface ElementHandler {
/**
* @param attacker Player performing elemental attack
* @param target Attack target
* @param damage Relative elemental damage
* @param absolute Absolute elemental damage dealt
*/
void elementAttack(PlayerMetadata attacker, LivingEntity target, double damage, double absolute);
}
public static class ElementParticle {
public final Consumer<Entity> display;

View File

@ -2,42 +2,52 @@ package net.Indyuce.mmoitems.api;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.player.PlayerMetadata;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Debug;
import java.nio.file.WatchKey;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* @deprecated Move this over to MythicLib ffs
* Also implementation is bad af
*/
@Deprecated
public class ElementalAttack {
private final PlayerMetadata attacker;
private final PlayerData playerData;
private final Map<Element, Double> relative = new HashMap<>();
private final Map<Element, Double> absolute = new HashMap<>();
private final ItemAttackMetadata attack;
private final LivingEntity target;
private final double initialDamage;
private static final Random random = new Random();
// TODO rework this shit
public ElementalAttack(NBTItem item, ItemAttackMetadata attack, LivingEntity target) {
this.attack = attack;
public ElementalAttack(PlayerMetadata attacker, NBTItem item, double initialDamage, LivingEntity target) {
this.initialDamage = initialDamage;
this.playerData = PlayerData.get(attacker.getPlayer());
this.attacker = attacker;
this.target = target;
for (Element element : Element.values()) {
double damage = item.getStat(element.name() + "_DAMAGE");
if (damage > 0) {
relative.put(element, damage);
double abs = damage / 100 * attack.getDamage().getDamage();
attack.getDamage().add(-abs);
absolute.put(element, abs);
absolute.put(element, damage / 100 * initialDamage);
}
}
}
public void apply() {
public double getDamageModifier() {
// elemental defense
// Elemental defense
for (ItemStack equip : target.getEquipment().getArmorContents()) {
NBTItem nbtEquip = MythicLib.plugin.getVersion().getWrapper().getNBTItem(equip);
if (nbtEquip.getType() != null)
@ -50,25 +60,31 @@ public class ElementalAttack {
}
}
// elemental attacks
// Elemental attacks
double p = 1;
if (!attack.getPlayerData().isOnCooldown(CooldownType.ELEMENTAL_ATTACK))
if (!playerData.isOnCooldown(CooldownType.ELEMENTAL_ATTACK))
for (Element element : relative.keySet()) {
double damage = relative.get(element);
if (random.nextDouble() < (damage / 100 / p)) {
attack.getPlayerData().applyCooldown(CooldownType.ELEMENTAL_ATTACK, 2);
element.getHandler().elementAttack(attack, target, damage, absolute.get(element));
double relativeDamage = relative.get(element);
if (random.nextDouble() < (relativeDamage / 100 / p)) {
playerData.applyCooldown(CooldownType.ELEMENTAL_ATTACK, 2);
element.getHandler().elementAttack(attacker, target, relativeDamage, absolute.get(element));
absolute.put(element, absolute.get(element) * 2);
break;
}
p -= damage / 100;
p -= relativeDamage / 100;
}
// Calculate final damage again
double finalDamage = 0;
for (Element element : absolute.keySet()) {
double damage = absolute.get(element);
if (damage > 0) {
attack.getDamage().add(damage);
double partialDamage = absolute.get(element);
if (partialDamage > 0) {
finalDamage += partialDamage;
element.getParticle().displayParticle(target);
}
}
return finalDamage - initialDamage;
}
}

View File

@ -68,7 +68,8 @@ public class ItemAttackMetadata extends AttackMetadata {
*/
@SuppressWarnings("UnusedReturnValue")
public ItemAttackMetadata applyElementalEffects(NBTItem item, LivingEntity target) {
new ElementalAttack(item, this, target).apply();
double damageModifier = new ElementalAttack(this, item, getDamage().getDamage(), target).getDamageModifier();
getDamage().add(damageModifier);
return this;
}
}

View File

@ -1,94 +0,0 @@
package net.Indyuce.mmoitems.api.event;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Called when a MMOItems arrow or trident entity is fired.
* <br><br>
* Contains information even on the temporary stats the player had when
* they executed the action, if that matters for some reason...
* <br><br>
* Note that this event fires before the projectile actually registers,
* be mindful of changes made to the temporary stats because they will
* affect the projectile.
*/
public class MMOItemsProjectileFireEvent extends Event {
/**
* @return The item the player used to fire this arrow.
*/
@NotNull public NBTItem getSourceItem() { return sourceItem; }
@NotNull NBTItem sourceItem;
/**
* Note that you must use {@link #setFinalDamage(double)} to modify the attack
* damage of the projectile rather than editing the attack damage of the player
* in here, as it will get overwritten.
*
* @return The stats the player had at the moment of firing the projectile.
*/
@NotNull public PlayerMetadata getPlayerStatsSnapshot() { return playerStatsSnapshot; }
@NotNull PlayerMetadata playerStatsSnapshot;
/**
* @return The projectile entity that was fired, arrow or trident.
*/
@NotNull public Entity getProjectile() { return projectile; }
@NotNull Entity projectile;
/**
* @return The damage this projectile will deal
*/
public double getFinalDamage() { return finalDamage; }
double finalDamage;
/**
* @param damage The damage this projectile will deal
*/
public void setFinalDamage(double damage) { finalDamage = damage; }
/**
* @return The original damage amount
*/
public double getDamageMultiplicator() { return damageMultiplicator; }
double damageMultiplicator;
/**
* @return The original damage amount
*/
public double getOriginalDamage() { return originalDamage; }
double originalDamage;
/**
* @return The kinds of damage this projectile will deal, what it will scale with.
*/
@NotNull public DamageType[] getDamageTypes() { return damageTypes; }
@NotNull DamageType[] damageTypes = { DamageType.PROJECTILE, DamageType.PHYSICAL, DamageType.WEAPON };
/**
* @param types The kinds of damage this projectile will deal, what it will scale with.
*/
public void setDamageTypes(@NotNull DamageType[] types) { damageTypes = types; }
/**
* @return The event that caused this projectile to be fired. Honestly, only for informational purposes of whatever listening API.
*/
@Nullable public EntityShootBowEvent getEvent() { return event; }
@Nullable EntityShootBowEvent event;
public MMOItemsProjectileFireEvent(@NotNull PlayerMetadata player, @NotNull Entity projectile, @NotNull NBTItem item, @Nullable EntityShootBowEvent event, double originalDamage, double damageMultiplicator) {
playerStatsSnapshot = player;
this.projectile = projectile;
sourceItem = item;
this.originalDamage = originalDamage;
this.damageMultiplicator= damageMultiplicator;
finalDamage = originalDamage * damageMultiplicator;
this.event = event;
}
//region Event Standard
private static final HandlerList handlers = new HandlerList();
@NotNull
@Override public HandlerList getHandlers() { return handlers; }
public static HandlerList getHandlerList() { return handlers; }
//endregion
}

View File

@ -6,6 +6,7 @@ import com.google.gson.JsonObject;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.damage.AttackMetadata;
import io.lumine.mythic.lib.player.PlayerMetadata;
import net.Indyuce.mmoitems.api.ItemAttackMetadata;
import net.Indyuce.mmoitems.stat.data.PotionEffectData;
import org.bukkit.entity.LivingEntity;
@ -13,11 +14,11 @@ import org.bukkit.potion.PotionEffectType;
public class ProjectileData {
private final NBTItem sourceItem;
private final ItemAttackMetadata attackMeta;
private final PlayerMetadata shooter;
private final boolean customWeapon;
public ProjectileData(NBTItem sourceItem, ItemAttackMetadata attackMeta, boolean customWeapon) {
this.attackMeta = attackMeta;
public ProjectileData(PlayerMetadata shooter, NBTItem sourceItem, boolean customWeapon) {
this.shooter = shooter;
this.sourceItem = sourceItem;
this.customWeapon = customWeapon;
}
@ -26,18 +27,43 @@ public class ProjectileData {
return sourceItem;
}
public ItemAttackMetadata getAttackMetadata() {
return attackMeta;
public PlayerMetadata getShooter() {
return shooter;
}
/*
* if the item is an item from MMOItems, apply on-hit effects like critical
* strikes, pvp/pve damage and elemental damage
/**
* Used to check if that projectile data is linked to
* a projectile that want sent using a MMOItems bow.
* <p>
* If so, it needs to apply on-hit effects like
* elemental damage or on-hit potion effects
*/
public boolean isCustomWeapon() {
return customWeapon;
}
/**
* Attack damage is handled in a weird fashion for projectile
* attacks. Attack damage is not stored in a simple field but
* rather the player's attack damage stat is temporarily changed.
* <p>
* Using this convention the attack damage is handled the same
* way for both melee and projectile attacks.
*
* @return Projectile damage, not taking into account crits and
* on-hit effects which are only applied afterwards by MythicLib
*/
public double getDamage() {
return shooter.getStat("ATTACK_DAMAGE");
}
/**
* @see {@link #getDamage()}
*/
public void setDamage(double damage) {
shooter.setStat("ATTACK_DAMAGE", damage);
}
public void applyPotionEffects(LivingEntity target) {
if (sourceItem.hasTag("MMOITEMS_ARROW_POTION_EFFECTS"))
for (JsonElement entry : MythicLib.plugin.getJson().parse(sourceItem.getString("MMOITEMS_ARROW_POTION_EFFECTS"), JsonArray.class)) {

View File

@ -6,13 +6,11 @@ import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.target.InteractionType;
import io.lumine.mythic.lib.damage.MeleeAttackMetadata;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.ItemAttackMetadata;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.TypeSet;
import net.Indyuce.mmoitems.api.event.MMOItemsProjectileFireEvent;
import net.Indyuce.mmoitems.api.event.MMOItemsSpecialWeaponAttack;
import net.Indyuce.mmoitems.api.interaction.*;
import net.Indyuce.mmoitems.api.interaction.weapon.Gauntlet;
@ -319,12 +317,12 @@ public class ItemUse implements Listener {
// Have to get hand manually because 1.15 and below does not have event.getHand()
ItemStack itemInMainHand = playerData.getPlayer().getInventory().getItemInMainHand();
EquipmentSlot bowSlot = (itemInMainHand.isSimilar(event.getBow())) ? EquipmentSlot.MAIN_HAND : EquipmentSlot.OFF_HAND;
EquipmentSlot bowSlot = itemInMainHand.isSimilar(event.getBow()) ? EquipmentSlot.MAIN_HAND : EquipmentSlot.OFF_HAND;
Arrow arrow = (Arrow) event.getProjectile();
if (item.getStat("ARROW_VELOCITY") > 0)
arrow.setVelocity(arrow.getVelocity().multiply(item.getStat("ARROW_VELOCITY")));
MMOItems.plugin.getEntities().registerCustomProjectile(item, playerData.getStats().newTemporary(bowSlot), event.getProjectile(), event, type != null, event.getForce());
MMOItems.plugin.getEntities().registerCustomProjectile(item, playerData.getStats().newTemporary(bowSlot), event.getProjectile(), type != null, event.getForce());
}
/**

View File

@ -5,11 +5,12 @@ import io.lumine.mythic.lib.damage.DamageMetadata;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.ElementalAttack;
import net.Indyuce.mmoitems.api.ItemAttackMetadata;
import net.Indyuce.mmoitems.api.event.MMOItemsProjectileFireEvent;
import net.Indyuce.mmoitems.api.interaction.projectile.ArrowParticles;
import net.Indyuce.mmoitems.api.interaction.projectile.EntityData;
import net.Indyuce.mmoitems.api.interaction.projectile.ProjectileData;
import net.Indyuce.mmoitems.api.player.PlayerData;
import org.bukkit.Bukkit;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Arrow;
@ -22,11 +23,13 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.WeakHashMap;
public class EntityManager implements Listener {
@ -40,8 +43,11 @@ public class EntityManager implements Listener {
private final WeakHashMap<Integer, ProjectileData> projectiles = new WeakHashMap<>();
@Deprecated public void registerCustomProjectile(NBTItem sourceItem, PlayerMetadata attacker, Entity entity, boolean customWeapon) { registerCustomProjectile(sourceItem, attacker, entity, customWeapon, 1); }
@Deprecated public void registerCustomProjectile(@NotNull NBTItem sourceItem, @NotNull PlayerMetadata attacker, @NotNull Entity entity, boolean customWeapon, double damageMultiplicator) { registerCustomProjectile(sourceItem, attacker, entity, null, customWeapon, damageMultiplicator); }
@Deprecated
public void registerCustomProjectile(NBTItem sourceItem, PlayerMetadata attacker, Entity entity, boolean customWeapon) {
registerCustomProjectile(sourceItem, attacker, entity, customWeapon, 1);
}
/**
* Registers a custom projectile. This is used for bows, crossbows and tridents.
* <p>
@ -49,34 +55,25 @@ public class EntityManager implements Listener {
*
* @param sourceItem Item used to shoot the projectile
* @param attacker Cached stats of the player shooting the projectile
* @param shootEvent Event that caused this projectile registration.
* @param entity The custom entity
* @param customWeapon Is the source weapon is a custom item
* @param damageMultiplicator The damage coefficient. For bows, this is basically the pull force.
* For tridents or anything else this is always set to 1
*/
public void registerCustomProjectile(@NotNull NBTItem sourceItem, @NotNull PlayerMetadata attacker, @NotNull Entity entity, @Nullable EntityShootBowEvent shootEvent, boolean customWeapon, double damageMultiplicator) {
public void registerCustomProjectile(@NotNull NBTItem sourceItem, @NotNull PlayerMetadata attacker, @NotNull Entity entity, boolean customWeapon, double damageMultiplicator) {
/*
* For bows, MC default value is 7. When using custom bows, the attack
* damage stats returns the correct amount of damage. When using a vanilla
* bow, attack damage is set to 1 because it's the default fist damage value.
* Therefore MMOItems adds 6 to match the vanilla bow damage which is 7.
* bow, attack damage is set to 2 because it's the default fist damage value.
* Therefore MMOItems adds 5 to match the vanilla bow damage which is 7.
*
* Damage coefficient is how much you pull the bow. It's something between 0
* and 1 for bows, and it's always 1 for tridents or crossbows.
*/
double damage = attacker.getStat("ATTACK_DAMAGE");
// Sweet event
MMOItemsProjectileFireEvent event = new MMOItemsProjectileFireEvent(attacker, entity, sourceItem, shootEvent, (customWeapon ? damage : 5 + damage), damageMultiplicator);
Bukkit.getPluginManager().callEvent(event);
// Update based one vent
double finalDamage = event.getFinalDamage();
ItemAttackMetadata attackMeta = new ItemAttackMetadata(new DamageMetadata(finalDamage, event.getDamageTypes()), attacker);
attacker.setStat("ATTACK_DAMAGE", finalDamage);
damage = (customWeapon ? damage : 5 + damage) * damageMultiplicator;
attacker.setStat("ATTACK_DAMAGE", damage);
/*
* Load arrow particles if the entity is an arrow and if the item has
@ -86,7 +83,7 @@ public class EntityManager implements Listener {
if (entity instanceof Arrow && sourceItem.hasTag("MMOITEMS_ARROW_PARTICLES"))
new ArrowParticles((Arrow) entity, sourceItem);
projectiles.put(entity.getEntityId(), new ProjectileData(sourceItem, attackMeta, customWeapon));
projectiles.put(entity.getEntityId(), new ProjectileData(attacker, sourceItem, customWeapon));
}
public void registerCustomEntity(Entity entity, EntityData data) {
@ -102,11 +99,11 @@ public class EntityManager implements Listener {
}
public ProjectileData getProjectileData(Projectile projectile) {
return projectiles.get(projectile.getEntityId());
return Objects.requireNonNull(projectiles.get(projectile.getEntityId()), "Provided entity is not a custom projectile");
}
public EntityData getEntityData(Entity entity) {
return entities.get(entity.getEntityId());
return Objects.requireNonNull(entities.get(entity.getEntityId()), "Provided entity is not a custom entity");
}
public void unregisterCustomProjectile(Projectile projectile) {
@ -134,19 +131,36 @@ public class EntityManager implements Listener {
ProjectileData data = getProjectileData(projectile);
LivingEntity target = (LivingEntity) event.getEntity();
double damage = data.getDamage();
// Apply power vanilla enchant
if (projectile instanceof Arrow && data.getSourceItem().getItem().hasItemMeta()
&& data.getSourceItem().getItem().getItemMeta().getEnchants().containsKey(Enchantment.ARROW_DAMAGE))
data.getAttackMetadata().getDamage().multiplicativeModifier(1.25 + (.25 * data.getSourceItem().getItem().getItemMeta().getEnchantLevel(Enchantment.ARROW_DAMAGE)), DamageType.WEAPON);
damage *= 1.25 + (.25 * data.getSourceItem().getItem().getItemMeta().getEnchantLevel(Enchantment.ARROW_DAMAGE));
// Apply MMOItems specific modifications
if (data.isCustomWeapon()) {
data.applyPotionEffects(target);
data.getAttackMetadata().applyElementalEffects(data.getSourceItem(), target);
damage += new ElementalAttack(data.getShooter(), data.getSourceItem(), damage, target).getDamageModifier();
}
event.setDamage(data.getAttackMetadata().getDamage().getDamage());
unregisterCustomProjectile(projectile);
event.setDamage(damage);
}
// Unregister custom projectiles from the map
@EventHandler(priority = EventPriority.HIGHEST)
public void c(EntityDamageByEntityEvent event) {
projectiles.remove(event.getEntity().getEntityId());
}
@EventHandler(priority = EventPriority.HIGHEST)
public void d(ProjectileHitEvent event) {
projectiles.remove(event.getEntity().getEntityId());
}
@EventHandler(priority = EventPriority.HIGHEST)
public void e(EntityDeathEvent event) {
projectiles.remove(event.getEntity().getEntityId());
}
}