attackMetadata slight changes ; better support for MM skill conditions

This commit is contained in:
Indyuce 2021-10-28 23:46:22 +02:00
parent 6e2fb4c19d
commit 3b8540b40d
10 changed files with 203 additions and 190 deletions

View File

@ -20,14 +20,12 @@ public class ItemAttackMetadata extends AttackMetadata {
super(damage, damager);
}
public PlayerData getPlayerData() {
return PlayerData.get(getDamager().getUniqueId());
public ItemAttackMetadata(AttackMetadata attackMeta) {
super(attackMeta.getDamage(), attackMeta.getStats());
}
@Override
public ItemAttackMetadata setSuccessful(boolean successful) {
super.setSuccessful(successful);
return this;
public PlayerData getPlayerData() {
return PlayerData.get(getDamager().getUniqueId());
}
/**

View File

@ -2,10 +2,12 @@ package net.Indyuce.mmoitems.api;
import io.lumine.mythic.lib.api.stat.modifier.ModifierSource;
import io.lumine.mythic.lib.comp.target.InteractionType;
import io.lumine.mythic.lib.damage.AttackMetadata;
import io.lumine.mythic.lib.version.VersionSound;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import org.bukkit.Location;
import org.bukkit.Particle;
@ -19,163 +21,163 @@ import java.util.Random;
public enum TypeSet {
/**
* Slashing weapons deal damage in a cone behind the player's initial
* target, which makes it a deadly AoE weapon for warriors
*/
SLASHING(ModifierSource.MELEE_WEAPON, (attack, target, weapon) -> {
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.slashing.enabled") || attack.getPlayerData().isOnCooldown(CooldownType.SET_TYPE_ATTACK))
return;
/**
* Slashing weapons deal damage in a cone behind the player's initial
* target, which makes it a deadly AoE weapon for warriors
*/
SLASHING(ModifierSource.MELEE_WEAPON, (attack, damager, target, weapon) -> {
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.slashing.enabled") || damager.isOnCooldown(CooldownType.SET_TYPE_ATTACK))
return;
attack.getPlayerData().applyCooldown(CooldownType.SET_TYPE_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.slashing.cooldown"));
Location loc = attack.getDamager().getLocation().clone().add(0, 1.3, 0);
damager.applyCooldown(CooldownType.SET_TYPE_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.slashing.cooldown"));
Location loc = attack.getDamager().getLocation().clone().add(0, 1.3, 0);
final double a1 = (loc.getYaw() + 90) / 180 * Math.PI, p = -loc.getPitch() / 180 * Math.PI;
for (double r = 1; r < 5; r += .3)
for (double a = -Math.PI / 6; a < Math.PI / 6; a += Math.PI / 8 / r)
loc.getWorld().spawnParticle(Particle.CRIT, loc.clone().add(Math.cos(a + a1) * r, Math.sin(p) * r, Math.sin(a + a1) * r), 0);
final double a1 = (loc.getYaw() + 90) / 180 * Math.PI, p = -loc.getPitch() / 180 * Math.PI;
for (double r = 1; r < 5; r += .3)
for (double a = -Math.PI / 6; a < Math.PI / 6; a += Math.PI / 8 / r)
loc.getWorld().spawnParticle(Particle.CRIT, loc.clone().add(Math.cos(a + a1) * r, Math.sin(p) * r, Math.sin(a + a1) * r), 0);
for (Entity entity : MMOUtils.getNearbyChunkEntities(loc))
if (entity.getLocation().distanceSquared(loc) < 40
&& attack.getDamager().getEyeLocation().getDirection()
.angle(entity.getLocation().subtract(attack.getDamager().getLocation()).toVector()) < Math.PI / 3
&& MMOUtils.canTarget(attack.getDamager(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target)) {
ItemAttackMetadata subAttack = new ItemAttackMetadata(attack.getDamage().clone(), attack.getStats());
subAttack.getDamage().multiply(.4);
subAttack.applyEffectsAndDamage(weapon.getNBTItem(), (LivingEntity) entity);
}
}),
for (Entity entity : MMOUtils.getNearbyChunkEntities(loc))
if (entity.getLocation().distanceSquared(loc) < 40
&& attack.getDamager().getEyeLocation().getDirection()
.angle(entity.getLocation().subtract(attack.getDamager().getLocation()).toVector()) < Math.PI / 3
&& MMOUtils.canTarget(attack.getDamager(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target)) {
ItemAttackMetadata subAttack = new ItemAttackMetadata(attack.getDamage().clone(), attack.getStats());
subAttack.getDamage().multiply(.4);
subAttack.applyEffectsAndDamage(weapon.getNBTItem(), (LivingEntity) entity);
}
}),
/**
* Piercing weapons deal damage in a line behind the initial target, which
* is harder to land than a slashing weapon but the AoE damage ratio is
* increased which makes it a perfect 'double or nothing' weapon for
* assassins
*/
PIERCING(ModifierSource.MELEE_WEAPON, (attack, target, weapon) -> {
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.piercing.enabled") || attack.getPlayerData().isOnCooldown(CooldownType.SET_TYPE_ATTACK))
return;
/**
* Piercing weapons deal damage in a line behind the initial target, which
* is harder to land than a slashing weapon but the AoE damage ratio is
* increased which makes it a perfect 'double or nothing' weapon for
* assassins
*/
PIERCING(ModifierSource.MELEE_WEAPON, (attack, damager, target, weapon) -> {
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.piercing.enabled") || damager.isOnCooldown(CooldownType.SET_TYPE_ATTACK))
return;
attack.getPlayerData().applyCooldown(CooldownType.SET_TYPE_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.piercing.cooldown"));
Location loc = attack.getDamager().getLocation().clone().add(0, 1.3, 0);
damager.applyCooldown(CooldownType.SET_TYPE_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.piercing.cooldown"));
Location loc = attack.getDamager().getLocation().clone().add(0, 1.3, 0);
final double a1 = (loc.getYaw() + 90) / 180 * Math.PI, p = -loc.getPitch() / 180 * Math.PI;
for (double r = 1; r < 5; r += .3)
for (double a = -Math.PI / 12; a < Math.PI / 12; a += Math.PI / 16 / r)
loc.getWorld().spawnParticle(Particle.CRIT, loc.clone().add(Math.cos(a + a1) * r, Math.sin(p) * r, Math.sin(a + a1) * r), 0);
final double a1 = (loc.getYaw() + 90) / 180 * Math.PI, p = -loc.getPitch() / 180 * Math.PI;
for (double r = 1; r < 5; r += .3)
for (double a = -Math.PI / 12; a < Math.PI / 12; a += Math.PI / 16 / r)
loc.getWorld().spawnParticle(Particle.CRIT, loc.clone().add(Math.cos(a + a1) * r, Math.sin(p) * r, Math.sin(a + a1) * r), 0);
for (Entity entity : MMOUtils.getNearbyChunkEntities(loc))
if (entity.getLocation().distanceSquared(attack.getDamager().getLocation()) < 40
&& attack.getDamager().getEyeLocation().getDirection()
.angle(entity.getLocation().toVector().subtract(attack.getDamager().getLocation().toVector())) < Math.PI / 18
&& MMOUtils.canTarget(attack.getDamager(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target)) {
ItemAttackMetadata subAttack = new ItemAttackMetadata(attack.getDamage().clone(), attack.getStats());
subAttack.getDamage().multiply(.4);
subAttack.applyEffectsAndDamage(weapon.getNBTItem(), (LivingEntity) entity);
}
}),
for (Entity entity : MMOUtils.getNearbyChunkEntities(loc))
if (entity.getLocation().distanceSquared(attack.getDamager().getLocation()) < 40
&& attack.getDamager().getEyeLocation().getDirection()
.angle(entity.getLocation().toVector().subtract(attack.getDamager().getLocation().toVector())) < Math.PI / 18
&& MMOUtils.canTarget(attack.getDamager(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target)) {
ItemAttackMetadata subAttack = new ItemAttackMetadata(attack.getDamage().clone(), attack.getStats());
subAttack.getDamage().multiply(.4);
subAttack.applyEffectsAndDamage(weapon.getNBTItem(), (LivingEntity) entity);
}
}),
/**
* Blunt weapons are like 1.9 sweep attacks. They damage all enemies nearby
* and apply a slight knockback
*/
BLUNT(ModifierSource.MELEE_WEAPON, (attack, target, weapon) -> {
final Random random = new Random();
float pitchRange = 0.7f + random.nextFloat() * (0.9f - 0.7f);
/**
* Blunt weapons are like 1.9 sweep attacks. They damage all enemies nearby
* and apply a slight knockback
*/
BLUNT(ModifierSource.MELEE_WEAPON, (attack, damager, target, weapon) -> {
final Random random = new Random();
float pitchRange = 0.7f + random.nextFloat() * (0.9f - 0.7f);
if (MMOItems.plugin.getConfig().getBoolean("item-ability.blunt.aoe.enabled")
&& !attack.getPlayerData().isOnCooldown(CooldownType.SPECIAL_ATTACK)) {
if (MMOItems.plugin.getConfig().getBoolean("item-ability.blunt.aoe.enabled")
&& !damager.isOnCooldown(CooldownType.SPECIAL_ATTACK)) {
attack.getPlayerData().applyCooldown(CooldownType.SPECIAL_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.blunt.aoe.cooldown"));
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 0.6f, pitchRange);
target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().add(0, 1, 0), 0);
double bluntPower = attack.getStats().getStat("BLUNT_POWER");
if (bluntPower > 0) {
double bluntRating = weapon.getValue(attack.getStats().getStat("BLUNT_RATING"),
MMOItems.plugin.getConfig().getDouble("default.blunt-rating")) / 100;
for (Entity entity : target.getNearbyEntities(bluntPower, bluntPower, bluntPower))
if (MMOUtils.canTarget(attack.getDamager(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target)) {
ItemAttackMetadata subAttack = new ItemAttackMetadata(attack.getDamage().clone(), attack.getStats());
subAttack.getDamage().multiply(bluntRating);
subAttack.applyEffectsAndDamage(weapon.getNBTItem(), (LivingEntity) entity);
}
}
}
damager.applyCooldown(CooldownType.SPECIAL_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.blunt.aoe.cooldown"));
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 0.6f, pitchRange);
target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().add(0, 1, 0), 0);
double bluntPower = attack.getStats().getStat("BLUNT_POWER");
if (bluntPower > 0) {
double bluntRating = weapon.getValue(attack.getStats().getStat("BLUNT_RATING"),
MMOItems.plugin.getConfig().getDouble("default.blunt-rating")) / 100;
for (Entity entity : target.getNearbyEntities(bluntPower, bluntPower, bluntPower))
if (MMOUtils.canTarget(attack.getDamager(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target)) {
ItemAttackMetadata subAttack = new ItemAttackMetadata(attack.getDamage().clone(), attack.getStats());
subAttack.getDamage().multiply(bluntRating);
subAttack.applyEffectsAndDamage(weapon.getNBTItem(), (LivingEntity) entity);
}
}
}
if (MMOItems.plugin.getConfig().getBoolean("item-ability.blunt.stun.enabled")
&& !attack.getPlayerData().isOnCooldown(CooldownType.SPECIAL_ATTACK)
&& random.nextDouble() < MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.chance") / 100) {
if (MMOItems.plugin.getConfig().getBoolean("item-ability.blunt.stun.enabled")
&& !damager.isOnCooldown(CooldownType.SPECIAL_ATTACK)
&& random.nextDouble() < MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.chance") / 100) {
attack.getPlayerData().applyCooldown(CooldownType.SPECIAL_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.cooldown"));
target.getWorld().playSound(target.getLocation(), VersionSound.ENTITY_ZOMBIE_ATTACK_WOODEN_DOOR.toSound(), 1, 2);
target.removePotionEffect(PotionEffectType.SLOW);
target.removePotionEffect(PotionEffectType.BLINDNESS);
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 0));
target.addPotionEffect(
new PotionEffect(PotionEffectType.SLOW, (int) (30 * MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.power")), 1));
Location loc = target.getLocation();
loc.setYaw((float) (loc.getYaw() + 2 * (random.nextDouble() - .5) * 90));
loc.setPitch((float) (loc.getPitch() + 2 * (random.nextDouble() - .5) * 30));
}
}),
damager.applyCooldown(CooldownType.SPECIAL_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.cooldown"));
target.getWorld().playSound(target.getLocation(), VersionSound.ENTITY_ZOMBIE_ATTACK_WOODEN_DOOR.toSound(), 1, 2);
target.removePotionEffect(PotionEffectType.SLOW);
target.removePotionEffect(PotionEffectType.BLINDNESS);
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 0));
target.addPotionEffect(
new PotionEffect(PotionEffectType.SLOW, (int) (30 * MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.power")), 1));
Location loc = target.getLocation();
loc.setYaw((float) (loc.getYaw() + 2 * (random.nextDouble() - .5) * 90));
loc.setPitch((float) (loc.getPitch() + 2 * (random.nextDouble() - .5) * 30));
}
}),
/**
* Any item type can may apply their stats even when worn in offhand.
* They're the only items with that specific property
*/
OFFHAND(ModifierSource.OTHER),
/**
* Any item type can may apply their stats even when worn in offhand.
* They're the only items with that specific property
*/
OFFHAND(ModifierSource.OTHER),
/**
* Ranged attacks based weapons. when the player is too squishy to fight in
* the middle of the battle-field, these weapons allow him to take some
* distance and still deal some good damage
*/
RANGE(ModifierSource.RANGED_WEAPON),
/**
* Ranged attacks based weapons. when the player is too squishy to fight in
* the middle of the battle-field, these weapons allow him to take some
* distance and still deal some good damage
*/
RANGE(ModifierSource.RANGED_WEAPON),
/**
* Any other item type, like armor, consumables, etc. They all have their
* very specific passive depending on their item type
*/
EXTRA(ModifierSource.OTHER);
/**
* Any other item type, like armor, consumables, etc. They all have their
* very specific passive depending on their item type
*/
EXTRA(ModifierSource.OTHER);
/**
* Interface between MMOItems' type sets and MythicLibs' modifierSources which let
* MythicLib know what type of item is giving some stat modifiers to a player
*/
private final ModifierSource modifierSource;
/**
* Interface between MMOItems' type sets and MythicLibs' modifierSources which let
* MythicLib know what type of item is giving some stat modifiers to a player
*/
private final ModifierSource modifierSource;
private final SetAttackHandler<ItemAttackMetadata, LivingEntity, Weapon> attackHandler;
private final String name;
private final SetAttackHandler attackHandler;
private final String name;
private TypeSet(ModifierSource modifierSource) {
this(modifierSource, null);
}
private TypeSet(ModifierSource modifierSource) {
this(modifierSource, null);
}
private TypeSet(ModifierSource modifierSource, SetAttackHandler<ItemAttackMetadata, LivingEntity, Weapon> attackHandler) {
this.attackHandler = attackHandler;
this.modifierSource = modifierSource;
private TypeSet(ModifierSource modifierSource, SetAttackHandler attackHandler) {
this.attackHandler = attackHandler;
this.modifierSource = modifierSource;
this.name = MMOUtils.caseOnWords(name().toLowerCase());
}
this.name = MMOUtils.caseOnWords(name().toLowerCase());
}
public ModifierSource getModifierSource() {
return modifierSource;
}
public ModifierSource getModifierSource() {
return modifierSource;
}
public boolean hasAttackEffect() {
return attackHandler != null;
}
public boolean hasAttackEffect() {
return attackHandler != null;
}
public void applyAttackEffect(ItemAttackMetadata attackMeta, LivingEntity target, Weapon weapon) {
attackHandler.apply(attackMeta, target, weapon);
}
public void applyAttackEffect(AttackMetadata attackMeta, PlayerData damager, LivingEntity target, Weapon weapon) {
attackHandler.apply(attackMeta, damager, target, weapon);
}
public String getName() {
return name;
}
public String getName() {
return name;
}
@FunctionalInterface
interface SetAttackHandler<A, B, C> {
void apply(A a, B b, C c);
}
@FunctionalInterface
interface SetAttackHandler {
void apply(AttackMetadata attack, PlayerData damager, LivingEntity target, Weapon weapon);
}
}

View File

@ -3,8 +3,8 @@ package net.Indyuce.mmoitems.api.interaction.weapon;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.comp.flags.CustomFlag;
import io.lumine.mythic.lib.damage.AttackMetadata;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.ItemAttackMetadata;
import net.Indyuce.mmoitems.api.interaction.UseItem;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
@ -81,19 +81,24 @@ public class Weapon extends UseItem {
return true;
}
public ItemAttackMetadata handleTargetedAttack(ItemAttackMetadata attackMeta, LivingEntity target) {
/**
* @param attackMeta The attack being performed
* @param target The attack target
* @return If the attack is successful, or if it was canceled otherwise
*/
public boolean handleTargetedAttack(AttackMetadata attackMeta, LivingEntity target) {
// Handle weapon cooldown, mana and stamina costs
double attackSpeed = getNBTItem().getStat(ItemStats.ATTACK_SPEED.getId());
attackSpeed = attackSpeed == 0 ? 1.493 : 1 / attackSpeed;
if (!applyWeaponCosts())
return attackMeta.setSuccessful(false);
return false;
// Handle item set attack effects
if (getMMOItem().getType().getItemSet().hasAttackEffect() && !getNBTItem().getBoolean("MMOITEMS_DISABLE_ATTACK_PASSIVE"))
getMMOItem().getType().getItemSet().applyAttackEffect(attackMeta, target, this);
getMMOItem().getType().getItemSet().applyAttackEffect(attackMeta, playerData, target, this);
return attackMeta;
return true;
}
protected Location getGround(Location loc) {

View File

@ -398,7 +398,7 @@ public class PlayerData {
*/
if (target == null ? !MythicLib.plugin.getFlags().isFlagAllowed(getPlayer(), CustomFlag.MMO_ABILITIES)
: !MythicLib.plugin.getFlags().isFlagAllowed(target.getLocation(), CustomFlag.MMO_ABILITIES))
return attack.setSuccessful(false);
return attack;
for (AbilityData ability : itemAbilities)
if (ability.getCastingMode() == castMode)

View File

@ -56,7 +56,7 @@ public class RealDualWieldHook implements Listener {
return;
}
if (!weapon.handleTargetedAttack(attackMeta = getAttack(playerData, event), target).isSuccessful()) {
if (!weapon.handleTargetedAttack(attackMeta = getAttack(playerData, event), target)) {
event.setCancelled(true);
return;
}

View File

@ -3,6 +3,7 @@ package net.Indyuce.mmoitems.comp.mmocore;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent;
import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.experience.Profession;
@ -104,12 +105,12 @@ public class MMOCoreHook implements RPGHandler, Listener {
@Override
public void giveMana(double value) {
data.giveMana(value);
data.giveMana(value, PlayerResourceUpdateEvent.UpdateReason.REGENERATION);
}
@Override
public void giveStamina(double value) {
data.giveStamina(value);
data.giveStamina(value, PlayerResourceUpdateEvent.UpdateReason.REGENERATION);
}
}
}

View File

@ -47,7 +47,11 @@ public class MythicMobsAbility extends Ability<MythicMobsAbilityMetadata> {
@Override
public void whenCast(ItemAttackMetadata attackMeta, MythicMobsAbilityMetadata ability) {
LivingEntity target = ability.getTarget();
skill.execute(ability.getSkillMetadata());
}
@Override
public MythicMobsAbilityMetadata canBeCast(ItemAttackMetadata attackMeta, LivingEntity target, AbilityData data) {
// TODO what's the difference between trigger and caster.
AbstractEntity trigger = BukkitAdapter.adapt(attackMeta.getDamager());
@ -58,20 +62,12 @@ public class MythicMobsAbility extends Ability<MythicMobsAbilityMetadata> {
targetEntities.add(BukkitAdapter.adapt(target));
SkillMetadata data = new SkillMetadata(SkillTrigger.CAST, caster, trigger, BukkitAdapter.adapt(attackMeta.getDamager().getEyeLocation()), targetEntities, targetLocations, 1);
SkillMetadata skillMeta = new SkillMetadata(SkillTrigger.CAST, caster, trigger, BukkitAdapter.adapt(attackMeta.getDamager().getEyeLocation()), targetEntities, targetLocations, 1);
// Stats are cached inside a variable
data.getVariables().putObject("MMOStatMap", attackMeta.getStats());
data.getVariables().putObject("MMOSkill", ability.getAbility());
skillMeta.getVariables().putObject("MMOStatMap", attackMeta.getStats());
skillMeta.getVariables().putObject("MMOSkill", data.getAbility());
if (skill.usable(data, SkillTrigger.CAST))
skill.execute(data);
else
attackMeta.setSuccessful(false);
}
@Override
public MythicMobsAbilityMetadata canBeCast(ItemAttackMetadata attackMeta, LivingEntity target, AbilityData data) {
return new MythicMobsAbilityMetadata(data, target);
return new MythicMobsAbilityMetadata(data, skill, skillMeta);
}
}

View File

@ -1,24 +1,28 @@
package net.Indyuce.mmoitems.comp.mythicmobs.skill;
import io.lumine.xikage.mythicmobs.skills.Skill;
import io.lumine.xikage.mythicmobs.skills.SkillMetadata;
import io.lumine.xikage.mythicmobs.skills.SkillTrigger;
import net.Indyuce.mmoitems.ability.AbilityMetadata;
import net.Indyuce.mmoitems.stat.data.AbilityData;
import org.bukkit.entity.LivingEntity;
public class MythicMobsAbilityMetadata extends AbilityMetadata {
private final LivingEntity target;
private final Skill skill;
private final SkillMetadata skillMeta;
public MythicMobsAbilityMetadata(AbilityData ability, LivingEntity target) {
public MythicMobsAbilityMetadata(AbilityData ability, Skill skill, SkillMetadata skillMeta) {
super(ability);
this.target = target;
this.skill = skill;
this.skillMeta = skillMeta;
}
public LivingEntity getTarget() {
return target;
public SkillMetadata getSkillMetadata() {
return skillMeta;
}
@Override
public boolean isSuccessful() {
return true;
return skill.usable(skillMeta, SkillTrigger.CAST);
}
}

View File

@ -1,6 +1,7 @@
package net.Indyuce.mmoitems.listener;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.stat.StatMap;
@ -104,29 +105,19 @@ public class ItemUse implements Listener {
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void meleeAttacks(EntityDamageByEntityEvent event) {
public void meleeAttacks(PlayerAttackEvent event) {
/*
* Citizens and Sentinels NPC support; damage = 0 check to ignore safety
* checks; check for entity attack
*/
if (event.getDamage() == 0 || event.getCause() != DamageCause.ENTITY_ATTACK || !(event.getEntity() instanceof LivingEntity)
|| !(event.getDamager() instanceof Player) || event.getEntity().hasMetadata("NPC") || event.getDamager().hasMetadata("NPC"))
return;
// Custom damage check
LivingEntity target = (LivingEntity) event.getEntity();
if (MythicLib.plugin.getDamage().findInfo(target) != null)
// Checks if the target is a damageable entity and if it's a melee attack
if (event.getBukkitCause() != DamageCause.ENTITY_ATTACK || !(event.getEntity() instanceof LivingEntity))
return;
/*
* Must apply attack conditions before apply any effects. the event must
* be cancelled before anything is applied
*/
Player player = (Player) event.getDamager();
Player player = event.getPlayer();
PlayerData playerData = PlayerData.get(player);
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(player.getInventory().getItemInMainHand());
ItemAttackMetadata attackMeta = null;
if (item.hasType() && Type.get(item.getType()) != Type.BLOCK) {
Weapon weapon = new Weapon(playerData, item);
@ -141,17 +132,14 @@ public class ItemUse implements Listener {
return;
}
if (!weapon.handleTargetedAttack(attackMeta = getAttack(playerData, event), target).isSuccessful()) {
if (!weapon.handleTargetedAttack(event.getAttack(), event.getEntity())) {
event.setCancelled(true);
return;
}
}
// Cast on-hit abilities and add the extra damage to the damage event
(attackMeta == null ? attackMeta = getAttack(playerData, event) : attackMeta).applyEffects(item, target);
// Finally update Bukkit event
event.setDamage(attackMeta.getDamage().getDamage());
new ItemAttackMetadata(event.getAttack()).applyEffects(item, event.getEntity());
}
private ItemAttackMetadata getAttack(PlayerData playerData, EntityDamageByEntityEvent event) {

View File

@ -180,9 +180,28 @@ public class PlayerListener implements Listener {
* Fixes an issue where quickly swapping items in hand just
* does not update the player's inventory which can make the
* player cast abilities or attacks with not the correct stats
*
* @deprecated This does cost some performance and that update
* method NEEDS some improvement in the future
*/
@Deprecated
@EventHandler
public void registerInventoryUpdates(PlayerSwapHandItemsEvent event) {
PlayerData.get(event.getPlayer()).updateInventory();
public void registerInventoryUpdates1(PlayerSwapHandItemsEvent event) {
PlayerData.get(event.getPlayer()).getInventory().scheduleUpdate();
}
/**
* Fixes an issue where quickly swapping items in hand just
* does not update the player's inventory which can make the
* player cast abilities or attacks with not the correct stats
*
* @deprecated This does cost some performance and that update
* method NEEDS some improvement in the future
*/
@Deprecated
@EventHandler
public void registerInventoryUpdates2(PlayerItemHeldEvent event) {
PlayerData.get(event.getPlayer()).getInventory().scheduleUpdate();
}
}