diff --git a/build.gradle b/build.gradle index 894fec093..8b08035cc 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id "dts.typescript-generator" } -version = "1.11-prerelease1" +version = "1.11-prerelease2" group= "kamkeel.customnpc-plus" archivesBaseName = "CustomNPC-Plus" diff --git a/dependencies.gradle b/dependencies.gradle index cd0322224..33eb048c1 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -35,7 +35,7 @@ */ def embedMixin = !project.hasProperty("nomixin"); dependencies { -// runtimeOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.5.4-GTNH:dev") + runtimeOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.8.44-GTNH:dev") if (!project.hasProperty("noNashorn")) { runtimeOnlyNonPublishable("curse.maven:Nashorn-374413:2924946") } diff --git a/src/api b/src/api index 319e77451..4ee1c41d0 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit 319e77451862a113b156c988a1234b2acbadfb2b +Subproject commit 4ee1c41d061eb4638b923cd3a430c7b63767ebdb diff --git a/src/main/java/kamkeel/npcs/controllers/EnergyController.java b/src/main/java/kamkeel/npcs/controllers/EnergyController.java index ffd25c400..5b6bc123a 100644 --- a/src/main/java/kamkeel/npcs/controllers/EnergyController.java +++ b/src/main/java/kamkeel/npcs/controllers/EnergyController.java @@ -1,12 +1,12 @@ package kamkeel.npcs.controllers; -import kamkeel.npcs.controllers.data.energy.IEnergyHandler; +import kamkeel.npcs.controllers.data.energy.IEnergyExtender; import kamkeel.npcs.entity.*; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; -import noppes.npcs.api.IEnergyController; +import noppes.npcs.api.IEnergyHandler; import noppes.npcs.api.IWorld; import noppes.npcs.api.entity.*; import noppes.npcs.api.entity.IEnergyExplosion; @@ -22,22 +22,22 @@ import java.util.List; * damage through registered handlers when entities have customDamageData * but no sourceAbility. */ -public class EnergyController implements IEnergyController { +public class EnergyController implements IEnergyHandler { public static EnergyController Instance = new EnergyController(); - private final List handlers = new ArrayList<>(); + private final List extenders = new ArrayList<>(); // ═══════════════════════════════════════════════════════════════════ // HANDLER REGISTRATION // ═══════════════════════════════════════════════════════════════════ - public void registerHandler(IEnergyHandler handler) { - handlers.add(handler); + public void registerExtender(IEnergyExtender handler) { + extenders.add(handler); } - public List getHandlers() { - return handlers; + public List getExtenders() { + return extenders; } // ═══════════════════════════════════════════════════════════════════ @@ -53,7 +53,7 @@ public class EnergyController implements IEnergyController { double kbDirX, double kbDirZ, float damageMultiplier, NBTTagCompound damageData) { - for (IEnergyHandler handler : handlers) { + for (IEnergyExtender handler : extenders) { if (handler.onEnergyDamage(energyEntity, owner, target, damage, knockback, knockbackUp, kbDirX, kbDirZ, damageMultiplier, damageData)) { return true; @@ -68,7 +68,7 @@ public class EnergyController implements IEnergyController { public float fireModifyEnergyDamage(Entity energyEntity, EntityLivingBase owner, float baseDamage, NBTTagCompound damageData) { float damage = baseDamage; - for (IEnergyHandler handler : handlers) { + for (IEnergyExtender handler : extenders) { damage = handler.modifyEnergyDamage(energyEntity, owner, damage, damageData); } return damage; @@ -150,7 +150,7 @@ public class EnergyController implements IEnergyController { } // ═══════════════════════════════════════════════════════════════════ - // IEnergyController (Script API methods) + // IEnergyHandler (Script API methods) // ═══════════════════════════════════════════════════════════════════ @Override diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/data/energy/EnergyBarrierData.java b/src/main/java/kamkeel/npcs/controllers/data/ability/data/energy/EnergyBarrierData.java index bfd48a3b3..40c30fe95 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/data/energy/EnergyBarrierData.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/data/energy/EnergyBarrierData.java @@ -32,6 +32,11 @@ public class EnergyBarrierData { // Absorbing: caster's damage is redirected to the barrier public boolean absorbing = false; + // Absorb radius: max distance from barrier's current position for absorption to work + // -1 = no radius limit (absorb regardless of distance) + // 0 = use barrier's own extent as the radius (dome radius, panel half-size, etc.) + // positive = owner must be within this many blocks of the barrier entity + public float absorbRadius = 0.0f; // Melee: barrier can be hit by melee attacks public boolean meleeEnabled = false; @@ -148,6 +153,14 @@ public class EnergyBarrierData { this.targetOwner = targetOwner; } + public float getAbsorbRadius() { + return absorbRadius; + } + + public void setAbsorbRadius(float absorbRadius) { + this.absorbRadius = absorbRadius; + } + // ==================== NBT ==================== public void writeNBT(NBTTagCompound nbt) { @@ -160,6 +173,7 @@ public class EnergyBarrierData { nbt.setBoolean("barrierKnockback", knockbackEnabled); nbt.setFloat("barrierKnockbackStr", knockbackStrength); nbt.setBoolean("barrierAbsorbing", absorbing); + nbt.setFloat("barrierAbsorbRadius", absorbRadius); nbt.setBoolean("barrierMelee", meleeEnabled); nbt.setFloat("barrierMeleeMult", meleeDamageMultiplier); nbt.setBoolean("barrierReflect", reflect); @@ -183,6 +197,7 @@ public class EnergyBarrierData { knockbackEnabled = nbt.hasKey("barrierKnockback") && nbt.getBoolean("barrierKnockback"); knockbackStrength = nbt.hasKey("barrierKnockbackStr") ? nbt.getFloat("barrierKnockbackStr") : 1.0f; absorbing = nbt.hasKey("barrierAbsorbing") && nbt.getBoolean("barrierAbsorbing"); + absorbRadius = nbt.hasKey("barrierAbsorbRadius") ? nbt.getFloat("barrierAbsorbRadius") : 0.0f; meleeEnabled = nbt.hasKey("barrierMelee") && nbt.getBoolean("barrierMelee"); meleeDamageMultiplier = nbt.hasKey("barrierMeleeMult") ? nbt.getFloat("barrierMeleeMult") : 1.0f; reflect = nbt.hasKey("barrierReflect") && nbt.getBoolean("barrierReflect"); @@ -207,6 +222,7 @@ public class EnergyBarrierData { copy.knockbackEnabled = knockbackEnabled; copy.knockbackStrength = knockbackStrength; copy.absorbing = absorbing; + copy.absorbRadius = absorbRadius; copy.meleeEnabled = meleeEnabled; copy.meleeDamageMultiplier = meleeDamageMultiplier; copy.reflect = reflect; diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityBarrier.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityBarrier.java index 5d12b4c11..1e3df2e02 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityBarrier.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityBarrier.java @@ -292,6 +292,14 @@ public abstract class AbilityBarrier extends AbilityEnergy { barrierData.absorbing = absorbing; } + public float getAbsorbRadius() { + return barrierData.absorbRadius; + } + + public void setAbsorbRadius(float radius) { + barrierData.absorbRadius = radius; + } + // Reflection data public boolean isReflect() { return barrierData.reflect; @@ -395,6 +403,9 @@ public abstract class AbilityBarrier extends AbilityEnergy { .range(0, 10).visibleWhen(this::isKnockbackEnabled)); defs.add(FieldDef.boolField("ability.absorbing", this::isAbsorbing, this::setAbsorbing) .hover("ability.hover.absorbing")); + defs.add(FieldDef.floatField("ability.absorbRadius", this::getAbsorbRadius, this::setAbsorbRadius) + .range(-1, 128).visibleWhen(this::isAbsorbing) + .hover("ability.hover.absorbRadius")); defs.add(FieldDef.boolField("ability.reflect", this::isReflect, this::setReflect) .hover("ability.hover.reflect")); defs.add(FieldDef.floatField("ability.reflectStrength", this::getReflectStrengthPct, this::setReflectStrengthPct) diff --git a/src/main/java/kamkeel/npcs/controllers/data/energy/IEnergyHandler.java b/src/main/java/kamkeel/npcs/controllers/data/energy/IEnergyExtender.java similarity index 98% rename from src/main/java/kamkeel/npcs/controllers/data/energy/IEnergyHandler.java rename to src/main/java/kamkeel/npcs/controllers/data/energy/IEnergyExtender.java index bd2e39a74..2dcd2fe43 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/energy/IEnergyHandler.java +++ b/src/main/java/kamkeel/npcs/controllers/data/energy/IEnergyExtender.java @@ -9,7 +9,7 @@ import net.minecraft.nbt.NBTTagCompound; * Registered with EnergyController. DBC Addon implements this to route * script-created energy entity damage through the DBC damage pipeline. */ -public interface IEnergyHandler { +public interface IEnergyExtender { /** * Handle damage for an energy entity with custom damage data. diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityZone.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityZone.java index 23120b80b..25e56cbd8 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityZone.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityZone.java @@ -321,6 +321,16 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD protected void entityInit() { } + @Override + protected void readEntityFromNBT(NBTTagCompound nbt) { + this.setDead(); + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbt) { + // Intentionally empty — ability entities are transient (not saved to world) + } + @Override public void handleHealthUpdate(byte id) { if (id == TRIGGER_FLASH_STATUS) { @@ -834,15 +844,6 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD // NBT SERIALIZATION // ═══════════════════════════════════════════════════════════════════ - @Override - protected void readEntityFromNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } // ═══════════════════════════════════════════════════════════════════ // SPAWN DATA (ByteBuf for client sync) diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java index 46c2647e8..9d6e8ab88 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java @@ -376,6 +376,22 @@ public abstract class EntityEnergyAbility extends Entity implements IEntityAddit magicData.readToNBT(nbt); } + // ==================== WORLD NBT (INTENTIONALLY EMPTY) ==================== + + /** + * Ability entities are transient — they must not survive world saves. + * If Minecraft deserializes one from a chunk, kill it immediately. + */ + @Override + protected void readEntityFromNBT(NBTTagCompound nbt) { + this.setDead(); + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbt) { + // Intentionally empty — ability entities are transient (not saved to world) + } + // ==================== SPAWN DATA ==================== /** diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyBarrier.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyBarrier.java index 872b7acb3..9683c2894 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyBarrier.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyBarrier.java @@ -630,7 +630,13 @@ public abstract class EntityEnergyBarrier extends EntityEnergyAbility { /** * Find a barrier that would absorb damage for the given entity (its caster). - * Returns the barrier if: absorbing is enabled AND entity is the barrier's owner. + * Returns the barrier if: absorbing is enabled, entity is the barrier's owner, + * and entity is within the barrier's absorb radius of the barrier's current position. + * + * Absorb radius behavior: + * -1 = no limit (absorb regardless of distance) + * 0 = uses the barrier's extent as the radius (dome radius, panel half-size, etc.) + * >0 = owner must be within this many blocks of the barrier entity */ public static EntityEnergyBarrier getAbsorbingBarrier(Entity entity) { if (entity == null || entity.worldObj == null) return null; @@ -638,7 +644,33 @@ public abstract class EntityEnergyBarrier extends EntityEnergyAbility { for (EntityEnergyBarrier barrier : barriers) { if (barrier.isDead) continue; if (!barrier.barrierData.absorbing) continue; - if (barrier.ownerEntityId == entity.getEntityId()) { + if (barrier.ownerEntityId != entity.getEntityId()) continue; + + float absorbRadius = barrier.barrierData.absorbRadius; + + // -1 = unlimited range + if (absorbRadius < 0) { + return barrier; + } + + // 0 = use barrier's own extent as the effective radius + // Domes: dome radius. Panels: max(width, height) * 0.5 + 1.0, doubled. + float effectiveRadius; + if (absorbRadius > 0) { + effectiveRadius = absorbRadius; + } else if (barrier instanceof EntityEnergyDome) { + effectiveRadius = barrier.getMaxExtent(); + } else { + effectiveRadius = barrier.getMaxExtent() * 3.0f; + } + + // Distance check from barrier's current position to the owner + double dx = entity.posX - barrier.posX; + double dy = (entity.posY + entity.height * 0.5) - barrier.posY; + double dz = entity.posZ - barrier.posZ; + double distSq = dx * dx + dy * dy + dz * dz; + + if (distSq <= (double) effectiveRadius * effectiveRadius) { return barrier; } } diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyDome.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyDome.java index c107b57f7..aa3e71759 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyDome.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyDome.java @@ -351,8 +351,10 @@ public class EntityEnergyDome extends EntityEnergyBarrier { double radialVel = ent.motionX * nx + ent.motionY * ny + ent.motionZ * nz; if (wasInside != isInside) { - // Entity crossed the boundary this tick — push back to original side - double pushDist = wasInside ? (r - 0.3) : (r + 0.3); + // Entity crossed the boundary this tick — push back to original side. + // Use a larger buffer (1.0) to prevent flying entities from crossing + // again in a single tick (their AI hard-sets motionY every tick). + double pushDist = wasInside ? (r - 1.0) : (r + 0.3); double surfaceX = posX + nx * pushDist; double surfaceY = posY + ny * pushDist - ent.height * 0.5; double surfaceZ = posZ + nz * pushDist; @@ -366,13 +368,16 @@ public class EntityEnergyDome extends EntityEnergyBarrier { teleportEntity(ent, surfaceX, surfaceY, surfaceZ); - // Cancel radial velocity and add corrective push + // Cancel radial velocity and add corrective push (all 3 axes). + // The Y component is critical for the dome top where nx/nz ≈ 0: + // without it, flying entities get no inward push at the apex. ent.motionX -= radialVel * nx; ent.motionY -= radialVel * ny; ent.motionZ -= radialVel * nz; double pushForce = wasInside ? -0.15 : 0.15; - if (canPushInDirection(ent, nx * pushForce, 0, nz * pushForce)) { + if (canPushInDirection(ent, nx * pushForce, ny * pushForce, nz * pushForce)) { ent.motionX += nx * pushForce; + ent.motionY += ny * pushForce; ent.motionZ += nz * pushForce; } ent.velocityChanged = true; @@ -387,8 +392,9 @@ public class EntityEnergyDome extends EntityEnergyBarrier { ent.motionY -= radialVel * ny; ent.motionZ -= radialVel * nz; double pushForce = isInside ? -0.05 : 0.05; - if (canPushInDirection(ent, nx * pushForce, 0, nz * pushForce)) { + if (canPushInDirection(ent, nx * pushForce, ny * pushForce, nz * pushForce)) { ent.motionX += nx * pushForce; + ent.motionY += ny * pushForce; ent.motionZ += nz * pushForce; } ent.velocityChanged = true; @@ -695,15 +701,6 @@ public class EntityEnergyDome extends EntityEnergyBarrier { // ==================== NBT ==================== - @Override - protected void readEntityFromNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } @Override protected void writeSpawnNBT(NBTTagCompound nbt) { diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyExplosion.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyExplosion.java index b23f1f269..8c69b6aa0 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyExplosion.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyExplosion.java @@ -289,15 +289,6 @@ public class EntityEnergyExplosion extends EntityEnergyAbility { // ==================== NBT ==================== - @Override - protected void readEntityFromNBT(NBTTagCompound nbt) { - // Intentionally empty - transient visual entity. - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbt) { - // Intentionally empty - transient visual entity. - } @Override protected void writeSpawnNBT(NBTTagCompound nbt) { diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyPanel.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyPanel.java index 0ec982fe7..77c5c680d 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyPanel.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyPanel.java @@ -730,15 +730,6 @@ public class EntityEnergyPanel extends EntityEnergyBarrier { // ==================== NBT ==================== - @Override - protected void readEntityFromNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } @Override protected void writeSpawnNBT(NBTTagCompound nbt) { diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java index 1d9c02fcc..c51949386 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java @@ -2413,15 +2413,6 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { // ==================== NBT ==================== - @Override - protected void readEntityFromNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } @Override protected void writeSpawnNBT(NBTTagCompound nbt) { diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergySweeper.java b/src/main/java/kamkeel/npcs/entity/EntityEnergySweeper.java index d8596cf08..0c5c48c23 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergySweeper.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergySweeper.java @@ -423,15 +423,6 @@ public class EntityEnergySweeper extends EntityEnergyAbility { // ==================== NBT ==================== - @Override - protected void readEntityFromNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbt) { - // Intentionally empty — ability entities are transient (not saved to world) - } @Override protected void writeSpawnNBT(NBTTagCompound nbt) { diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index be2be429a..67a55f58d 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -124,7 +124,7 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; -@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.11-prerelease1") +@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.11-prerelease2") public class CustomNpcs { @SidedProxy(clientSide = "noppes.npcs.client.ClientProxy", serverSide = "noppes.npcs.CommonProxy") diff --git a/src/main/java/noppes/npcs/scripted/NpcAPI.java b/src/main/java/noppes/npcs/scripted/NpcAPI.java index fd301b802..1b0d392b2 100644 --- a/src/main/java/noppes/npcs/scripted/NpcAPI.java +++ b/src/main/java/noppes/npcs/scripted/NpcAPI.java @@ -63,7 +63,7 @@ import noppes.npcs.api.IBlock; import noppes.npcs.api.ICommand; import noppes.npcs.api.IContainer; import noppes.npcs.api.IDamageSource; -import noppes.npcs.api.IEnergyController; +import noppes.npcs.api.IEnergyHandler; import noppes.npcs.api.INbt; import noppes.npcs.api.IParticle; import noppes.npcs.api.IPos; @@ -623,7 +623,7 @@ public class NpcAPI extends AbstractNpcAPI { } @Override - public IEnergyController getEnergyController() { + public IEnergyHandler getEnergyHandler() { return EnergyController.Instance; } diff --git a/src/main/java/noppes/npcs/scripted/entity/ScriptEnergyBarrier.java b/src/main/java/noppes/npcs/scripted/entity/ScriptEnergyBarrier.java index f18b86320..16d96ddc1 100644 --- a/src/main/java/noppes/npcs/scripted/entity/ScriptEnergyBarrier.java +++ b/src/main/java/noppes/npcs/scripted/entity/ScriptEnergyBarrier.java @@ -121,6 +121,14 @@ public class ScriptEnergyBarrier extends ScriptEn entity.getBarrierData().absorbing = absorbing; } + public float getAbsorbRadius() { + return entity.getBarrierData().absorbRadius; + } + + public void setAbsorbRadius(float radius) { + entity.getBarrierData().absorbRadius = radius; + } + public boolean isReflect() { return entity.getBarrierData().reflect; } diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang index 913a3a257..f375c56c2 100644 --- a/src/main/resources/assets/customnpcs/lang/en_US.lang +++ b/src/main/resources/assets/customnpcs/lang/en_US.lang @@ -2165,6 +2165,7 @@ ability.solid=Solid ability.knockbackEnabled=Knockback ability.knockbackStrength=Knockback Strength ability.absorbing=Absorbing +ability.absorbRadius=Absorb Radius ability.reflect=Reflect ability.reflectStrength=Strength (%) ability.meleeEnabled=Allows Melee @@ -2175,6 +2176,7 @@ ability.hover.followCaster=Dome stays centered on the caster as they move ability.hover.solid=Entities cannot pass through the barrier boundary ability.hover.knockbackEnabled=Repulsion field pushing entities away from barrier surface ability.hover.absorbing=Damage dealt to the caster is redirected to the barrier's health +ability.hover.absorbRadius=Max distance from the barrier for absorption to work. -1 = unlimited, 0 = barrier extent (dome radius or panel size x3), positive = block radius ability.hover.reflect=Rebounds non-breaking projectiles and reduces their damage by Strength ability.targetOwner=Target Owner ability.hover.targetOwner=Sets the reflected projectile's target to the original caster. With homing enabled, the projectile will home toward its former caster.