diff --git a/core/src/main/java/com/nisovin/magicspells/events/SpellPreImpactEvent.java b/core/src/main/java/com/nisovin/magicspells/events/SpellPreImpactEvent.java index e4b0aabb0..dfef93493 100644 --- a/core/src/main/java/com/nisovin/magicspells/events/SpellPreImpactEvent.java +++ b/core/src/main/java/com/nisovin/magicspells/events/SpellPreImpactEvent.java @@ -7,46 +7,54 @@ import com.nisovin.magicspells.Spell; import com.nisovin.magicspells.MagicSpells; +import com.nisovin.magicspells.util.SpellData; import com.nisovin.magicspells.handlers.DebugHandler; public class SpellPreImpactEvent extends SpellEvent implements Cancellable { - private LivingEntity target; - private float power; - private Spell deliverySpell; + private final Spell deliverySpell; + + private SpellData spellData; + private boolean redirect; private boolean cancelled; + @Deprecated public SpellPreImpactEvent(Spell spellPayload, Spell deliverySpell, LivingEntity caster, LivingEntity target, float power) { - super(spellPayload, caster); - this.target = target; - this.power = power; + this(spellPayload, deliverySpell, new SpellData(caster, target, power)); + } + + public SpellPreImpactEvent(Spell spellPayload, Spell deliverySpell, SpellData spellData) { + super(spellPayload, spellData.caster()); this.deliverySpell = deliverySpell; - redirect = false; - cancelled = false; + this.spellData = spellData; if (DebugHandler.isSpellPreImpactEventCheckEnabled()) MagicSpells.plugin.getLogger().info(toString()); } - + public LivingEntity getTarget() { - return target; + return spellData.target(); } public boolean getRedirected() { return redirect; } - + public void setRedirected(boolean redirect) { this.redirect = redirect; } - + public float getPower() { - return power; + return spellData.power(); } - + public void setPower(float power) { - this.power = power; + spellData = spellData.power(power); } - + + public SpellData getSpellData() { + return spellData; + } + public Spell getDeliverySpell() { return deliverySpell; } @@ -60,14 +68,14 @@ public boolean isCancelled() { public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } - + @Override public String toString() { - String casterLabel = "Caster: " + (caster == null ? "null" : caster.toString()); - String targetLabel = "Target: " + (target == null ? "null" : target.toString()); - String spellLabel = "SpellPayload: " + (spell == null ? "null" : spell.toString()); - String payloadSpellLabel = "Delivery Spell: " + (deliverySpell == null ? "null" : deliverySpell.toString()); + String casterLabel = "Caster: " + caster; + String targetLabel = "Target: " + spellData.target(); + String spellLabel = "SpellPayload: " + (spell == null ? "null" : spell.getInternalName()); + String payloadSpellLabel = "Delivery Spell: " + (deliverySpell == null ? "null" : deliverySpell.getInternalName()); return Arrays.deepToString(new String[]{ casterLabel, targetLabel, spellLabel, payloadSpellLabel }); } - + } diff --git a/core/src/main/java/com/nisovin/magicspells/events/SpellTargetEvent.java b/core/src/main/java/com/nisovin/magicspells/events/SpellTargetEvent.java index 7a0745000..a80e0856d 100644 --- a/core/src/main/java/com/nisovin/magicspells/events/SpellTargetEvent.java +++ b/core/src/main/java/com/nisovin/magicspells/events/SpellTargetEvent.java @@ -91,6 +91,14 @@ public SpellData getSpellData() { return spellData; } + /** + * Sets the spell's {@link SpellData} to the provided value. + * @param data the new data + */ + public void setSpellData(SpellData data) { + spellData = data; + } + @Override public boolean isCancelled() { return cancelled; diff --git a/core/src/main/java/com/nisovin/magicspells/spells/buff/ReflectSpell.java b/core/src/main/java/com/nisovin/magicspells/spells/buff/ReflectSpell.java index 0ce98afb5..ef7b05460 100644 --- a/core/src/main/java/com/nisovin/magicspells/spells/buff/ReflectSpell.java +++ b/core/src/main/java/com/nisovin/magicspells/spells/buff/ReflectSpell.java @@ -18,9 +18,9 @@ // NO API CHANGES - NEEDS TOTAL REWORK public class ReflectSpell extends BuffSpell { - private final Map reflectors; - private final Set shieldBreakerNames; - private final Set delayedReflectionSpells; + private final Map reflectors = new HashMap<>(); + private final Set shieldBreakerNames = new HashSet<>(); + private final Set delayedReflectionSpells = new HashSet<>(); private final ConfigData reflectedSpellPowerMultiplier; @@ -31,10 +31,6 @@ public class ReflectSpell extends BuffSpell { public ReflectSpell(MagicConfig config, String spellName) { super(config, spellName); - reflectors = new HashMap<>(); - shieldBreakerNames = new HashSet<>(); - delayedReflectionSpells = new HashSet<>(); - shieldBreakerNames.addAll(getConfigStringList("shield-breakers", new ArrayList<>())); delayedReflectionSpells.addAll(getConfigStringList("delayed-reflection-spells", new ArrayList<>())); @@ -93,17 +89,15 @@ public void onSpellTarget(SpellTargetEvent event) { if (!target.isValid()) return; if (!isActive(target)) return; - if (shieldBreakerNames != null && shieldBreakerNames.contains(event.getSpell().getInternalName())) { + if (shieldBreakerNames.contains(event.getSpell().getInternalName())) { turnOff(target); return; } - if (delayedReflectionSpells != null && delayedReflectionSpells.contains(event.getSpell().getInternalName())) { - // Let the delayed reflection spells target the reflector so the animations run - // It will get reflected later - return; - } - event.setTarget(event.getCaster()); + // Let the delayed reflection spells target the reflector so the reflection is handled on impact instead. + if (delayedReflectionSpells.contains(event.getSpell().getInternalName())) return; + + event.setSpellData(event.getSpellData().invert()); ReflectData data = reflectors.get(target.getUniqueId()); addUseAndChargeCost(target); diff --git a/core/src/main/java/com/nisovin/magicspells/spells/instant/BeamSpell.java b/core/src/main/java/com/nisovin/magicspells/spells/instant/BeamSpell.java index 3a8022cb4..49947c669 100644 --- a/core/src/main/java/com/nisovin/magicspells/spells/instant/BeamSpell.java +++ b/core/src/main/java/com/nisovin/magicspells/spells/instant/BeamSpell.java @@ -19,6 +19,7 @@ import com.nisovin.magicspells.events.SpellTargetEvent; import com.nisovin.magicspells.zones.NoMagicZoneManager; import com.nisovin.magicspells.spells.TargetedEntitySpell; +import com.nisovin.magicspells.events.SpellPreImpactEvent; import com.nisovin.magicspells.spelleffects.EffectPosition; import com.nisovin.magicspells.spells.TargetedLocationSpell; import com.nisovin.magicspells.spells.TargetedEntityFromLocationSpell; @@ -268,7 +269,7 @@ public CastResult castAtEntityFromLocation(SpellData data) { //check entities in the beam range for (LivingEntity e : loc.getNearbyLivingEntities(hitRadius, verticalHitRadius)) { if (!e.isValid() || immune.contains(e)) continue; - if (!validTargetList.canTarget(data.caster(), e)) continue; + if (!validTargetList.canTarget(locData.caster(), e)) continue; SpellTargetEvent event = new SpellTargetEvent(this, locData, e); if (!event.callEvent()) continue; @@ -276,19 +277,30 @@ public CastResult castAtEntityFromLocation(SpellData data) { SpellData subData = event.getSpellData(); LivingEntity entity = event.getTarget(); - if (hitSpell != null) hitSpell.subcast(subData.noLocation()); if (entityLocationSpell != null) entityLocationSpell.subcast(subData.noTarget()); + if (hitSpell != null) { + SpellPreImpactEvent preImpact = new SpellPreImpactEvent(hitSpell.getSpell(), BeamSpell.this, subData); + if (preImpact.callEvent()) { + subData = preImpact.getSpellData(); + + if (preImpact.getRedirected()) { + step.multiply(-1); + locData = subData.caster(entity); + continue mainLoop; + } else hitSpell.subcast(subData.noLocation()); + } + } playSpellEffects(EffectPosition.TARGET, entity, subData); - playSpellEffectsTrail(data.caster().getLocation(), entity.getLocation(), subData); - immune.add(e); + playSpellEffectsTrail(subData.caster().getLocation(), entity.getLocation(), subData); + immune.add(entity); if (stopOnHitEntity) break mainLoop; } } //end of the beam if (!zoneManager.willFizzle(loc, this) && d >= maxDistance) { - playSpellEffects(EffectPosition.DELAYED, loc, data.location(loc)); + playSpellEffects(EffectPosition.DELAYED, loc, locData.location(loc)); if (endSpell != null) endSpell.subcast(locData); } diff --git a/core/src/main/java/com/nisovin/magicspells/spells/instant/BlockBeamSpell.java b/core/src/main/java/com/nisovin/magicspells/spells/instant/BlockBeamSpell.java index 33d553f54..0accaaf67 100644 --- a/core/src/main/java/com/nisovin/magicspells/spells/instant/BlockBeamSpell.java +++ b/core/src/main/java/com/nisovin/magicspells/spells/instant/BlockBeamSpell.java @@ -14,7 +14,6 @@ import org.bukkit.entity.ArmorStand; import org.bukkit.event.EventHandler; import org.bukkit.inventory.ItemStack; -import org.bukkit.attribute.Attribute; import org.bukkit.entity.LivingEntity; import org.bukkit.persistence.PersistentDataType; @@ -28,6 +27,7 @@ import com.nisovin.magicspells.util.magicitems.MagicItem; import com.nisovin.magicspells.util.magicitems.MagicItems; import com.nisovin.magicspells.spells.TargetedEntitySpell; +import com.nisovin.magicspells.events.SpellPreImpactEvent; import com.nisovin.magicspells.spelleffects.EffectPosition; import com.nisovin.magicspells.spells.TargetedLocationSpell; import com.nisovin.magicspells.spells.TargetedEntityFromLocationSpell; @@ -298,7 +298,7 @@ public CastResult castAtEntityFromLocation(SpellData data) { stand.getPersistentDataContainer().set(MS_BLOCK_BEAM, PersistentDataType.BOOLEAN, true); if (hpFix) { - stand.getAttribute(Attribute.MAX_HEALTH).setBaseValue(health); + Util.setMaxHealth(stand, health); stand.setHealth(health); } @@ -310,7 +310,7 @@ public CastResult castAtEntityFromLocation(SpellData data) { //check entities in the beam range for (LivingEntity e : loc.getNearbyLivingEntities(hitRadius, verticalHitRadius)) { if (!e.isValid() || immune.contains(e)) continue; - if (!validTargetList.canTarget(data.caster(), e)) continue; + if (!validTargetList.canTarget(locData.caster(), e)) continue; SpellTargetEvent event = new SpellTargetEvent(this, locData, e); if (!event.callEvent()) continue; @@ -318,10 +318,21 @@ public CastResult castAtEntityFromLocation(SpellData data) { SpellData subData = event.getSpellData(); LivingEntity subTarget = event.getTarget(); - if (hitSpell != null) hitSpell.subcast(subData.noLocation()); + if (hitSpell != null) { + SpellPreImpactEvent preImpact = new SpellPreImpactEvent(hitSpell.getSpell(), BlockBeamSpell.this, subData); + if (preImpact.callEvent()) { + subData = preImpact.getSpellData(); + + if (preImpact.getRedirected()) { + step.multiply(-1); + locData = subData.caster(e); + continue mainLoop; + } else hitSpell.subcast(subData.noLocation()); + } + } playSpellEffects(EffectPosition.TARGET, subTarget, subData); - playSpellEffectsTrail(data.caster().getLocation(), subTarget.getLocation(), subData); + playSpellEffectsTrail(subData.caster().getLocation(), subTarget.getLocation(), subData); immune.add(e); if (stopOnHitEntity) break mainLoop; @@ -330,7 +341,7 @@ public CastResult castAtEntityFromLocation(SpellData data) { //end of the beam if (!zoneManager.willFizzle(loc, this) && d >= maxDistance) { - playSpellEffects(EffectPosition.DELAYED, loc, data.location(loc)); + playSpellEffects(EffectPosition.DELAYED, loc, locData.location(loc)); if (endSpell != null) endSpell.subcast(locData); } diff --git a/core/src/main/java/com/nisovin/magicspells/spells/instant/ProjectileSpell.java b/core/src/main/java/com/nisovin/magicspells/spells/instant/ProjectileSpell.java index d2316db1f..f8efc8e92 100644 --- a/core/src/main/java/com/nisovin/magicspells/spells/instant/ProjectileSpell.java +++ b/core/src/main/java/com/nisovin/magicspells/spells/instant/ProjectileSpell.java @@ -6,7 +6,6 @@ import org.bukkit.Location; import org.bukkit.entity.*; import org.bukkit.util.Vector; -import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.entity.PotionSplashEvent; import org.bukkit.event.entity.EntityExplodeEvent; @@ -286,40 +285,27 @@ public void onCreatureSpawn(CreatureSpawnEvent event) { } @EventHandler - public void onProjectileHit(ProjectileHitEvent e) { - Projectile projectile = e.getEntity(); - Block block = e.getHitBlock(); - Entity entity = e.getHitEntity(); + public void onProjectileHit(ProjectileHitEvent event) { + Projectile projectile = event.getEntity(); - Iterator iterator = trackerSet.iterator(); + Set trackers = new HashSet<>(trackerSet); + for (ProjectileTracker tracker : trackers) { + if (!projectile.equals(tracker.getProjectile())) continue; + + SpellData subData = tracker.getSpellData(); - if (block != null) { - while (iterator.hasNext()) { - ProjectileTracker tracker = iterator.next(); - if (tracker.getProjectile() == null) continue; - if (!tracker.getProjectile().equals(projectile)) continue; + if (event.getHitBlock() != null) { + subData = subData.location(projectile.getLocation()); - SpellData subData = tracker.getSpellData().location(projectile.getLocation()); if (tracker.getGroundSpell() != null) tracker.getGroundSpell().subcast(subData); - tracker.stop(false); - iterator.remove(); + + tracker.stop(); break; } - } - - if (entity instanceof LivingEntity livingEntity) { - while (iterator.hasNext()) { - ProjectileTracker tracker = iterator.next(); - if (tracker.getProjectile() == null) continue; - if (!tracker.getProjectile().equals(projectile)) continue; - - SpellData subData = tracker.getSpellData().target(livingEntity); - if (tracker.getHitSpell() != null) tracker.getHitSpell().subcast(subData); - playSpellEffects(EffectPosition.TARGET, livingEntity, subData); - e.setCancelled(true); - tracker.stop(false); - iterator.remove(); + if (event.getHitEntity() instanceof LivingEntity target) { + event.setCancelled(true); + tracker.hitEntity(target, subData.target(target)); break; } } diff --git a/core/src/main/java/com/nisovin/magicspells/spells/targeted/HomingMissileSpell.java b/core/src/main/java/com/nisovin/magicspells/spells/targeted/HomingMissileSpell.java index ded7648eb..36c5dd678 100644 --- a/core/src/main/java/com/nisovin/magicspells/spells/targeted/HomingMissileSpell.java +++ b/core/src/main/java/com/nisovin/magicspells/spells/targeted/HomingMissileSpell.java @@ -18,8 +18,8 @@ import com.nisovin.magicspells.Subspell; import com.nisovin.magicspells.MagicSpells; import com.nisovin.magicspells.spells.TargetedSpell; -import com.nisovin.magicspells.util.compat.EventUtil; import com.nisovin.magicspells.util.config.ConfigData; +import com.nisovin.magicspells.events.SpellTargetEvent; import com.nisovin.magicspells.zones.NoMagicZoneManager; import com.nisovin.magicspells.spelleffects.SpellEffect; import com.nisovin.magicspells.castmodifiers.ModifierSet; @@ -414,30 +414,35 @@ public void run() { counter++; if (hitSpell == null) return; - hitBox.setCenter(currentLocation); - if (hitBox.contains(targetLoc)) { - SpellPreImpactEvent preImpact = new SpellPreImpactEvent(hitSpell.getSpell(), HomingMissileSpell.this, data.caster(), data.target(), data.power()); - EventUtil.call(preImpact); - // Should we bounce the missile back? - if (!preImpact.getRedirected()) { - // Apparently didn't get redirected, carry out the plans - hitSpell.subcast(data.noLocation()); - if (entityLocationSpell != null) entityLocationSpell.subcast(data.noTarget()); - - playSpellEffects(EffectPosition.TARGET, data.target(), data); - if (stopOnHitTarget) stop(); - } else { - if (!data.hasCaster()) { - stop(); - return; - } + if (!hitBox.contains(targetLoc)) return; - currentVelocity.multiply(-1); - data = data.power(preImpact.getPower()).invert(); - } + SpellTargetEvent targetEvent = new SpellTargetEvent(HomingMissileSpell.this, data); + if (!targetEvent.callEvent()) return; + SpellData subData = targetEvent.getSpellData(); + + SpellPreImpactEvent preImpact = new SpellPreImpactEvent(hitSpell.getSpell(), HomingMissileSpell.this, subData); + if (!preImpact.callEvent()) { + if (stopOnHitTarget) stop(); + return; } + subData = preImpact.getSpellData(); + if (preImpact.getRedirected()) { + if (!subData.hasCaster()) { + stop(); + return; + } + + currentVelocity.multiply(-1); + data = subData.invert(); + } else { + hitSpell.subcast(subData.noLocation()); + if (entityLocationSpell != null) entityLocationSpell.subcast(subData.noTarget()); + + playSpellEffects(EffectPosition.TARGET, subData.target(), subData); + if (stopOnHitTarget) stop(); + } } private void playIntermediateEffectLocations(Location old, Vector movement) { diff --git a/core/src/main/java/com/nisovin/magicspells/spells/targeted/HomingProjectileSpell.java b/core/src/main/java/com/nisovin/magicspells/spells/targeted/HomingProjectileSpell.java index bb038b66d..cdb496686 100644 --- a/core/src/main/java/com/nisovin/magicspells/spells/targeted/HomingProjectileSpell.java +++ b/core/src/main/java/com/nisovin/magicspells/spells/targeted/HomingProjectileSpell.java @@ -23,6 +23,7 @@ import com.nisovin.magicspells.events.SpellTargetEvent; import com.nisovin.magicspells.zones.NoMagicZoneManager; import com.nisovin.magicspells.castmodifiers.ModifierSet; +import com.nisovin.magicspells.events.SpellPreImpactEvent; import com.nisovin.magicspells.spells.TargetedEntitySpell; import com.nisovin.magicspells.util.config.ConfigDataUtil; import com.nisovin.magicspells.spelleffects.EffectPosition; @@ -382,15 +383,33 @@ public void run() { counter++; + if (hitSpell == null) return; hitBox.setCenter(currentLocation); - if (hitBox.contains(targetLoc)) { - SpellTargetEvent targetEvent = new SpellTargetEvent(HomingProjectileSpell.this, data); - if (!targetEvent.callEvent()) return; - data = targetEvent.getSpellData(); + if (!hitBox.contains(targetLoc)) return; - if (hitSpell != null) hitSpell.subcast(data.noLocation()); - playSpellEffects(EffectPosition.TARGET, data.target(), data); + SpellTargetEvent targetEvent = new SpellTargetEvent(HomingProjectileSpell.this, data); + if (!targetEvent.callEvent()) return; + SpellData subData = targetEvent.getSpellData(); + SpellPreImpactEvent preImpact = new SpellPreImpactEvent(hitSpell.getSpell(), HomingProjectileSpell.this, subData); + if (!preImpact.callEvent()) { + stop(); + return; + } + subData = preImpact.getSpellData(); + + if (preImpact.getRedirected()) { + if (!subData.hasCaster()) { + stop(); + return; + } + + currentVelocity.multiply(-1); + data = subData.invert(); + } else { + hitSpell.subcast(subData.noLocation()); + + playSpellEffects(EffectPosition.TARGET, subData.target(), subData); stop(); } } diff --git a/core/src/main/java/com/nisovin/magicspells/spells/targeted/ProjectileModifySpell.java b/core/src/main/java/com/nisovin/magicspells/spells/targeted/ProjectileModifySpell.java index d0437992a..795b360d8 100644 --- a/core/src/main/java/com/nisovin/magicspells/spells/targeted/ProjectileModifySpell.java +++ b/core/src/main/java/com/nisovin/magicspells/spells/targeted/ProjectileModifySpell.java @@ -1,7 +1,6 @@ package com.nisovin.magicspells.spells.targeted; import java.util.List; -import java.util.HashSet; import java.util.Iterator; import org.apache.commons.math4.core.jdkmath.AccurateMath; @@ -237,8 +236,6 @@ public CastResult castAtLocation(SpellData data) { double hRadiusSquared = box.getHorizontalRadius() * box.getHorizontalRadius(); double vRadiusSquared = box.getVerticalRadius() * box.getVerticalRadius(); - Iterator iterator = new HashSet<>(ParticleProjectileSpell.getProjectileTrackers()).iterator(); - int maxTargets = this.maxTargets.get(data); int cone = this.cone.get(data); @@ -252,11 +249,11 @@ public CastResult castAtLocation(SpellData data) { boolean affectOwnedProjectiles = this.affectOwnedProjectiles.get(data); boolean affectEnemyProjectiles = this.affectEnemyProjectiles.get(data); - Location currentLoc; + Iterator iterator = ParticleProjectileSpell.getProjectileTrackers().iterator(); while (iterator.hasNext()) { ParticleProjectileTracker tracker = iterator.next(); if (tracker == null || tracker.isStopped()) continue; - currentLoc = tracker.getCurrentLocation(); + Location currentLoc = tracker.getCurrentLocation(); if (currentLoc == null) continue; if (!currentLoc.getWorld().equals(location.getWorld())) continue; if (!box.contains(currentLoc)) continue; diff --git a/core/src/main/java/com/nisovin/magicspells/spells/targeted/VolleySpell.java b/core/src/main/java/com/nisovin/magicspells/spells/targeted/VolleySpell.java index 6980b63ad..c7ca0f8fe 100644 --- a/core/src/main/java/com/nisovin/magicspells/spells/targeted/VolleySpell.java +++ b/core/src/main/java/com/nisovin/magicspells/spells/targeted/VolleySpell.java @@ -7,7 +7,6 @@ import org.bukkit.Registry; import org.bukkit.util.Vector; import org.bukkit.entity.Arrow; -import org.bukkit.entity.Entity; import org.bukkit.event.Listener; import org.bukkit.potion.PotionType; import org.bukkit.event.EventHandler; @@ -17,6 +16,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.entity.AbstractArrow; import org.bukkit.event.entity.EntityRemoveEvent; +import org.bukkit.event.entity.ProjectileHitEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; @@ -139,24 +139,35 @@ public void turnOff() { private static class ArrowListener implements Listener { @EventHandler - public void onArrowHit(EntityDamageByEntityEvent event) { - if (event.getCause() != DamageCause.PROJECTILE || !(event.getEntity() instanceof LivingEntity target)) return; - - Entity damagerEntity = event.getDamager(); - if (!(damagerEntity instanceof Arrow arrow)) return; + public void onArrowDamage(EntityDamageByEntityEvent event) { + if (event.getCause() != DamageCause.PROJECTILE) return; + if (!(event.getDamager() instanceof Arrow arrow)) return; VolleyData data = ARROW_DATA.get(arrow.getUniqueId()); if (data == null) return; event.setDamage(data.damage); + } + + @EventHandler + public void onArrowHit(ProjectileHitEvent event) { + if (!(event.getEntity() instanceof Arrow arrow)) return; + if (!(event.getHitEntity() instanceof LivingEntity target)) return; + + VolleyData data = ARROW_DATA.get(arrow.getUniqueId()); + if (data == null) return; + + SpellPreImpactEvent preImpact = new SpellPreImpactEvent(data.spell, data.spell, new SpellData((LivingEntity) arrow.getShooter(), target)); + if (!preImpact.callEvent()) { + event.setCancelled(true); + return; + } - SpellPreImpactEvent preImpactEvent = new SpellPreImpactEvent(data.spell, data.spell, (LivingEntity) arrow.getShooter(), target, 1); - preImpactEvent.callEvent(); - if (!preImpactEvent.getRedirected()) return; + if (!preImpact.getRedirected()) return; event.setCancelled(true); + arrow.setShooter(target); arrow.setVelocity(arrow.getVelocity().multiply(-1)); - arrow.teleportAsync(arrow.getLocation().add(arrow.getVelocity())); } @EventHandler(priority = EventPriority.MONITOR) diff --git a/core/src/main/java/com/nisovin/magicspells/util/trackers/ItemProjectileTracker.java b/core/src/main/java/com/nisovin/magicspells/util/trackers/ItemProjectileTracker.java index 4ab92e5b8..99f67e664 100644 --- a/core/src/main/java/com/nisovin/magicspells/util/trackers/ItemProjectileTracker.java +++ b/core/src/main/java/com/nisovin/magicspells/util/trackers/ItemProjectileTracker.java @@ -14,10 +14,10 @@ import com.nisovin.magicspells.MagicSpells; import com.nisovin.magicspells.util.SpellData; import com.nisovin.magicspells.util.ValidTargetList; -import com.nisovin.magicspells.util.compat.EventUtil; import com.nisovin.magicspells.events.SpellTargetEvent; import com.nisovin.magicspells.events.TrackerMoveEvent; import com.nisovin.magicspells.zones.NoMagicZoneManager; +import com.nisovin.magicspells.events.SpellPreImpactEvent; import com.nisovin.magicspells.spelleffects.EffectPosition; import com.nisovin.magicspells.spells.instant.ItemProjectileSpell; @@ -139,11 +139,8 @@ public void run() { currentLocation.setDirection(entity.getVelocity()); if (callEvents) { - TrackerMoveEvent trackerMoveEvent = new TrackerMoveEvent(this, previousLocation, currentLocation); - EventUtil.call(trackerMoveEvent); - if (stopped) { - return; - } + new TrackerMoveEvent(this, previousLocation, currentLocation).callEvent(); + if (stopped) return; } data = data.location(currentLocation); @@ -163,11 +160,23 @@ public void run() { SpellTargetEvent event = new SpellTargetEvent(spell, data, target); if (!event.callEvent()) continue; - SpellData subData = event.getSpellData(); if (spell != null) spell.playEffects(EffectPosition.TARGET, subData.target(), subData); - if (spellOnHitEntity != null) spellOnHitEntity.subcast(subData.noLocation()); + + if (spellOnHitEntity != null) { + SpellPreImpactEvent preImpact = new SpellPreImpactEvent(spellOnHitEntity.getSpell(), spell, subData); + if (preImpact.callEvent()) { + subData = preImpact.getSpellData(); + + if (preImpact.getRedirected()) { + setCaster(subData.target()); + entity.setVelocity(entity.getVelocity().multiply(-1)); + return; + } else spellOnHitEntity.subcast(subData.noLocation()); + } + } + if (stopOnHitEntity) stop(); return; } diff --git a/core/src/main/java/com/nisovin/magicspells/util/trackers/ParticleProjectileTracker.java b/core/src/main/java/com/nisovin/magicspells/util/trackers/ParticleProjectileTracker.java index 415b6f76c..d917b9e64 100644 --- a/core/src/main/java/com/nisovin/magicspells/util/trackers/ParticleProjectileTracker.java +++ b/core/src/main/java/com/nisovin/magicspells/util/trackers/ParticleProjectileTracker.java @@ -24,12 +24,12 @@ import com.nisovin.magicspells.util.*; import com.nisovin.magicspells.Subspell; import com.nisovin.magicspells.MagicSpells; -import com.nisovin.magicspells.util.compat.EventUtil; import com.nisovin.magicspells.events.TrackerMoveEvent; import com.nisovin.magicspells.events.SpellTargetEvent; import com.nisovin.magicspells.spelleffects.SpellEffect; import com.nisovin.magicspells.zones.NoMagicZoneManager; import com.nisovin.magicspells.castmodifiers.ModifierSet; +import com.nisovin.magicspells.events.SpellPreImpactEvent; import com.nisovin.magicspells.spelleffects.EffectPosition; import com.nisovin.magicspells.events.ParticleProjectileHitEvent; import com.nisovin.magicspells.spelleffects.util.EffectlibSpellEffect; @@ -309,11 +309,8 @@ public void run() { previousLocation = Util.makeFinite(previousLocation); if (callEvents) { - TrackerMoveEvent trackerMoveEvent = new TrackerMoveEvent(this, previousLocation, currentLocation); - EventUtil.call(trackerMoveEvent); - if (stopped) { - return; - } + new TrackerMoveEvent(this, previousLocation, currentLocation).callEvent(); + if (stopped) return; } if (hugSurface) { @@ -418,9 +415,8 @@ public void run() { if (stopped) return; if (spell == null || interactions == null || interactions.isEmpty()) return; - Set toRemove = new HashSet<>(); - Set trackers = new HashSet<>(ParticleProjectileSpell.getProjectileTrackers()); - for (ParticleProjectileTracker collisionTracker : trackers) { + + for (ParticleProjectileTracker collisionTracker : new HashSet<>(ParticleProjectileSpell.getProjectileTrackers())) { boolean isCaster = Objects.equals(data.caster(), collisionTracker.data.caster()); for (Interaction interaction : interactions) { @@ -436,21 +432,10 @@ public void run() { interaction.collisionSpell().subcast(data.location(middleLoc)); } - if (interaction.stopCausing()) { - toRemove.add(collisionTracker); - collisionTracker.stop(false); - } - - if (interaction.stopWith()) { - toRemove.add(this); - stop(false); - } + if (interaction.stopCausing()) collisionTracker.stop(); + if (interaction.stopWith()) stop(); } } - - ParticleProjectileSpell.getProjectileTrackers().removeAll(toRemove); - toRemove.clear(); - trackers.clear(); } private boolean canInteractWith(ParticleProjectileTracker collisionTracker) { @@ -558,8 +543,18 @@ private void checkHitbox(Location currentLoc) { target = targetEvent.getTarget(); if (casterSpell != null && target.equals(data.caster())) casterSpell.subcast(subData, false, false, HIT_ORDERING); - if (entitySpell != null && !target.equals(data.caster())) entitySpell.subcast(subData, false, false, HIT_ORDERING); if (entityLocationSpell != null) entityLocationSpell.subcast(subData.noTarget()); + if (entitySpell != null && !target.equals(data.caster())) { + SpellPreImpactEvent preImpact = new SpellPreImpactEvent(entitySpell.getSpell(), spell, subData); + if (preImpact.callEvent()) { + subData = preImpact.getSpellData(); + + if (preImpact.getRedirected()) { + setCaster(subData.target()); + currentVelocity.multiply(-1); + } else entitySpell.subcast(subData, false, false, HIT_ORDERING); + } + } if (spell != null) spell.playEffects(EffectPosition.TARGET, currentLoc, subData); diff --git a/core/src/main/java/com/nisovin/magicspells/util/trackers/ProjectileTracker.java b/core/src/main/java/com/nisovin/magicspells/util/trackers/ProjectileTracker.java index 662023b93..b873fc227 100644 --- a/core/src/main/java/com/nisovin/magicspells/util/trackers/ProjectileTracker.java +++ b/core/src/main/java/com/nisovin/magicspells/util/trackers/ProjectileTracker.java @@ -19,12 +19,12 @@ import com.nisovin.magicspells.Subspell; import com.nisovin.magicspells.MagicSpells; import com.nisovin.magicspells.util.projectile.*; -import com.nisovin.magicspells.util.compat.EventUtil; import com.nisovin.magicspells.events.SpellTargetEvent; import com.nisovin.magicspells.events.TrackerMoveEvent; import com.nisovin.magicspells.zones.NoMagicZoneManager; import com.nisovin.magicspells.spelleffects.SpellEffect; import com.nisovin.magicspells.castmodifiers.ModifierSet; +import com.nisovin.magicspells.events.SpellPreImpactEvent; import com.nisovin.magicspells.spelleffects.EffectPosition; import com.nisovin.magicspells.spells.instant.ProjectileSpell; import com.nisovin.magicspells.spelleffects.util.EffectlibSpellEffect; @@ -191,8 +191,7 @@ public void run() { currentLocation.setDirection(projectile.getVelocity()); if (callEvents) { - TrackerMoveEvent trackerMoveEvent = new TrackerMoveEvent(this, previousLocation, currentLocation); - EventUtil.call(trackerMoveEvent); + new TrackerMoveEvent(this, previousLocation, currentLocation).callEvent(); if (stopped) return; } @@ -289,19 +288,37 @@ public void checkHitbox(Location location) { SpellData data = this.data.location(location); - for (LivingEntity entity : location.getNearbyLivingEntities(hitRadius, verticalHitRadius, hitRadius)) { - if (!targetList.canTarget(data.caster(), entity)) continue; + for (LivingEntity entity : location.getNearbyLivingEntities(hitRadius, verticalHitRadius)) + if (hitEntity(entity, data)) + break; + } - SpellTargetEvent event = new SpellTargetEvent(spell, data, entity); - if (!event.callEvent()) continue; + public boolean hitEntity(LivingEntity entity, SpellData data) { + if (!targetList.canTarget(data.caster(), entity)) return false; - SpellData subData = event.getSpellData(); - if (hitSpell != null) hitSpell.subcast(subData.noLocation()); - if (entityLocationSpell != null) entityLocationSpell.subcast(subData.noTarget()); + SpellTargetEvent event = new SpellTargetEvent(spell, data, entity); + if (!event.callEvent()) return false; - stop(); - return; + SpellData subData = event.getSpellData(); + + if (entityLocationSpell != null) entityLocationSpell.subcast(subData.noTarget()); + if (hitSpell != null) { + SpellPreImpactEvent preImpact = new SpellPreImpactEvent(hitSpell.getSpell(), spell, subData); + if (preImpact.callEvent()) { + subData = preImpact.getSpellData(); + + if (preImpact.getRedirected()) { + setCaster(subData.target()); + projectile.setVelocity(projectile.getVelocity().multiply(-1)); + return true; + } else hitSpell.subcast(subData.noLocation()); + } } + + spell.playEffects(EffectPosition.TARGET, subData.target(), subData); + + stop(); + return true; } @Override