mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2025-03-13 13:30:06 +01:00
Improved implementation of elemental and projectile attacks to match new ML tools
This commit is contained in:
parent
3ba7839833
commit
4cc82848bd
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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)) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user