diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyAnchorData.java b/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyAnchorData.java new file mode 100644 index 000000000..39c7db9e7 --- /dev/null +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyAnchorData.java @@ -0,0 +1,54 @@ +package kamkeel.npcs.controllers.data.ability.data; + +import kamkeel.npcs.controllers.data.ability.AnchorPoint; +import net.minecraft.nbt.NBTTagCompound; + +public class EnergyAnchorData { + public AnchorPoint anchorPoint = AnchorPoint.FRONT; + public float anchorOffsetX = 0; + public float anchorOffsetY = 0; + public float anchorOffsetZ = 0; + + public EnergyAnchorData() { + } + + public EnergyAnchorData(AnchorPoint anchorPoint) { + this.anchorPoint = anchorPoint; + } + + public EnergyAnchorData(AnchorPoint anchorPoint, float anchorOffsetX, float anchorOffsetY, float anchorOffsetZ) { + this.anchorPoint = anchorPoint; + this.anchorOffsetX = anchorOffsetX; + this.anchorOffsetY = anchorOffsetY; + this.anchorOffsetZ = anchorOffsetZ; + } + + public EnergyAnchorData(int anchorPoint) { + this.anchorPoint = AnchorPoint.fromId(anchorPoint); + } + + public EnergyAnchorData(int anchorPoint, float anchorOffsetX, float anchorOffsetY, float anchorOffsetZ) { + this.anchorPoint = AnchorPoint.fromId(anchorPoint); + this.anchorOffsetX = anchorOffsetX; + this.anchorOffsetY = anchorOffsetY; + this.anchorOffsetZ = anchorOffsetZ; + } + + public void writeNBT(NBTTagCompound nbt) { + nbt.setInteger("anchorPoint", anchorPoint.getId()); + nbt.setFloat("anchorOffsetX", anchorOffsetX); + nbt.setFloat("anchorOffsetY", anchorOffsetY); + nbt.setFloat("anchorOffsetZ", anchorOffsetZ); + } + + public void readNBT(NBTTagCompound nbt) { + this.anchorPoint = nbt.hasKey("anchorPoint") ? AnchorPoint.fromId(nbt.getInteger("anchorPoint")) : AnchorPoint.FRONT; + this.anchorOffsetX = nbt.hasKey("anchorOffsetX") ? nbt.getFloat("anchorOffsetX") : 0; + this.anchorOffsetY = nbt.hasKey("anchorOffsetY") ? nbt.getFloat("anchorOffsetY") : 0; + this.anchorOffsetZ = nbt.hasKey("anchorOffsetZ") ? nbt.getFloat("anchorOffsetZ") : 0; + } + + public EnergyAnchorData copy() { + return new EnergyAnchorData(anchorPoint, anchorOffsetX, anchorOffsetY, anchorOffsetZ); + } +} diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java index b80dcbdef..3ef2e164d 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java @@ -6,11 +6,7 @@ import kamkeel.npcs.controllers.data.ability.Ability; import kamkeel.npcs.controllers.data.ability.AnchorPoint; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; -import kamkeel.npcs.controllers.data.ability.data.EnergyColorData; -import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData; -import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData; +import kamkeel.npcs.controllers.data.ability.data.*; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; @@ -19,7 +15,6 @@ import kamkeel.npcs.util.AnchorPointHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.DamageSource; import net.minecraft.util.Vec3; import net.minecraft.world.World; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; @@ -42,15 +37,13 @@ public class AbilityDisc extends Ability implements IAbilityDisc { private boolean boomerang = false; private int boomerangDelay = 40; - // Anchor point for charging position - private AnchorPoint anchorPoint = AnchorPoint.RIGHT_HAND; - // Energy data classes private EnergyColorData colorData = new EnergyColorData(0xFFFFFF, 0xFF8800, true, 0.4f, 0.5f, 5.0f); private EnergyCombatData combatData = new EnergyCombatData(8.0f, 1.2f, 0.15f, false, 3.0f, 0.5f); private EnergyHomingData homingData = new EnergyHomingData(0.6f, true, 0.12f, 18.0f); private EnergyLightningData lightningData = new EnergyLightningData(); private EnergyLifespanData lifespanData = new EnergyLifespanData(35.0f, 200); + private EnergyAnchorData anchorData = new EnergyAnchorData(AnchorPoint.RIGHT_HAND); // Transient state for disc entity (used during windup charging) private transient EntityAbilityDisc discEntity = null; @@ -115,14 +108,14 @@ public class AbilityDisc extends Ability implements IAbilityDisc { // Spawn disc in charging mode on first tick of windup if (tick == 1) { // Create disc in charging mode - follows NPC based on anchor point during windup - Vec3 spawnPos = AnchorPointHelper.calculateAnchorPosition(npc, anchorPoint); + Vec3 spawnPos = AnchorPointHelper.calculateAnchorPosition(npc, anchorData); discEntity = new EntityAbilityDisc( world, npc, target, spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord, discRadius, discThickness, colorData, combatData, homingData, lightningData, lifespanData, boomerang, boomerangDelay); - discEntity.setupCharging(anchorPoint, windUpTicks); + discEntity.setupCharging(anchorData, windUpTicks); discEntity.setEffects(this.effects); world.spawnEntityInWorld(discEntity); @@ -184,7 +177,7 @@ public class AbilityDisc extends Ability implements IAbilityDisc { nbt.setFloat("discThickness", discThickness); nbt.setBoolean("boomerang", boomerang); nbt.setInteger("boomerangDelay", boomerangDelay); - nbt.setInteger("anchorPoint", anchorPoint.getId()); + anchorData.writeNBT(nbt); colorData.writeNBT(nbt); combatData.writeNBT(nbt); homingData.writeNBT(nbt); @@ -198,7 +191,7 @@ public class AbilityDisc extends Ability implements IAbilityDisc { this.discThickness = nbt.hasKey("discThickness") ? nbt.getFloat("discThickness") : 0.2f; this.boomerang = nbt.hasKey("boomerang") && nbt.getBoolean("boomerang"); this.boomerangDelay = nbt.hasKey("boomerangDelay") ? nbt.getInteger("boomerangDelay") : 40; - this.anchorPoint = nbt.hasKey("anchorPoint") ? AnchorPoint.fromId(nbt.getInteger("anchorPoint")) : AnchorPoint.FRONT; + anchorData.readNBT(nbt); colorData.readNBT(nbt); combatData.readNBT(nbt); homingData.readNBT(nbt); @@ -257,14 +250,20 @@ public class AbilityDisc extends Ability implements IAbilityDisc { public void setLightningDensity(float lightningDensity) { lightningData.lightningDensity = lightningDensity; } public float getLightningRadius() { return lightningData.lightningRadius; } public void setLightningRadius(float lightningRadius) { lightningData.lightningRadius = lightningRadius; } - public AnchorPoint getAnchorPointEnum() { return anchorPoint; } - public void setAnchorPointEnum(AnchorPoint anchorPoint) { this.anchorPoint = anchorPoint; } + public AnchorPoint getAnchorPointEnum() { return anchorData.anchorPoint; } + public float getAnchorOffsetX() { return anchorData.anchorOffsetX; } + public float getAnchorOffsetY() { return anchorData.anchorOffsetY; } + public float getAnchorOffsetZ() { return anchorData.anchorOffsetZ; } + public void setAnchorPointEnum(AnchorPoint anchorPoint) { this.anchorData.anchorPoint = anchorPoint; } + public void setAnchorOffsetX(float x) { this.anchorData.anchorOffsetX = x; } + public void setAnchorOffsetY(float y) { this.anchorData.anchorOffsetY = y; } + public void setAnchorOffsetZ(float z) { this.anchorData.anchorOffsetZ = z; } @Override - public int getAnchorPoint() { return anchorPoint.getId(); } + public int getAnchorPoint() { return anchorData.anchorPoint.getId(); } @Override - public void setAnchorPoint(int point) { this.anchorPoint = AnchorPoint.fromId(point); } + public void setAnchorPoint(int point) { this.anchorData.anchorPoint = AnchorPoint.fromId(point); } @Override @SideOnly(Side.CLIENT) @@ -272,7 +271,7 @@ public class AbilityDisc extends Ability implements IAbilityDisc { if (npc == null || npc.worldObj == null) return null; EntityAbilityDisc disc = new EntityAbilityDisc(npc.worldObj); - disc.setupPreview(npc, discRadius, discThickness, colorData, lightningData, anchorPoint, windUpTicks); + disc.setupPreview(npc, discRadius, discThickness, colorData, lightningData, anchorData, windUpTicks); return disc; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java index 049c4c281..53377161a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java @@ -6,11 +6,7 @@ import kamkeel.npcs.controllers.data.ability.Ability; import kamkeel.npcs.controllers.data.ability.AnchorPoint; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; -import kamkeel.npcs.controllers.data.ability.data.EnergyColorData; -import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData; -import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData; +import kamkeel.npcs.controllers.data.ability.data.*; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; @@ -44,9 +40,7 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { private EnergyHomingData homingData = new EnergyHomingData(0.4f, true, 0.1f, 15.0f); private EnergyLightningData lightningData = new EnergyLightningData(); private EnergyLifespanData lifespanData = new EnergyLifespanData(25.0f, 200); - - // Anchor point for charging position - private AnchorPoint anchorPoint = AnchorPoint.RIGHT_HAND; + private EnergyAnchorData anchorData = new EnergyAnchorData(AnchorPoint.RIGHT_HAND); // Transient state for beam entity (used during windup charging) private transient EntityAbilityBeam beamEntity = null; @@ -113,14 +107,14 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { float offsetDist = 1.0f; // Create beam in charging mode - follows NPC based on anchor point during windup - Vec3 spawnPos = AnchorPointHelper.calculateAnchorPosition(npc, anchorPoint, offsetDist); + Vec3 spawnPos = AnchorPointHelper.calculateAnchorPosition(npc, anchorData, offsetDist); beamEntity = new EntityAbilityBeam( world, npc, target, spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord, beamWidth, headSize, colorData, combatData, homingData, lightningData, lifespanData, lockMovement.locksActive()); - beamEntity.setupCharging(anchorPoint, windUpTicks, offsetDist); + beamEntity.setupCharging(anchorData, windUpTicks, offsetDist); beamEntity.setEffects(this.effects); world.spawnEntityInWorld(beamEntity); @@ -180,7 +174,7 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { public void writeTypeNBT(NBTTagCompound nbt) { nbt.setFloat("beamWidth", beamWidth); nbt.setFloat("headSize", headSize); - nbt.setInteger("anchorPoint", anchorPoint.getId()); + anchorData.writeNBT(nbt); colorData.writeNBT(nbt); combatData.writeNBT(nbt); homingData.writeNBT(nbt); @@ -192,7 +186,7 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { public void readTypeNBT(NBTTagCompound nbt) { this.beamWidth = nbt.hasKey("beamWidth") ? nbt.getFloat("beamWidth") : 0.4f; this.headSize = nbt.hasKey("headSize") ? nbt.getFloat("headSize") : 0.6f; - this.anchorPoint = nbt.hasKey("anchorPoint") ? AnchorPoint.fromId(nbt.getInteger("anchorPoint")) : AnchorPoint.FRONT; + anchorData.readNBT(nbt); colorData.readNBT(nbt); combatData.readNBT(nbt); homingData.readNBT(nbt); @@ -259,14 +253,20 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { public void setMaxLifetime(int maxLifetime) { this.lifespanData.maxLifetime = maxLifetime; } // Getters & Setters - Anchor point - public AnchorPoint getAnchorPointEnum() { return anchorPoint; } - public void setAnchorPointEnum(AnchorPoint anchorPoint) { this.anchorPoint = anchorPoint; } + public AnchorPoint getAnchorPointEnum() { return anchorData.anchorPoint; } + public float getAnchorOffsetX() { return anchorData.anchorOffsetX; } + public float getAnchorOffsetY() { return anchorData.anchorOffsetY; } + public float getAnchorOffsetZ() { return anchorData.anchorOffsetZ; } + public void setAnchorPointEnum(AnchorPoint anchorPoint) { this.anchorData.anchorPoint = anchorPoint; } + public void setAnchorOffsetX(float x) { this.anchorData.anchorOffsetX = x; } + public void setAnchorOffsetY(float y) { this.anchorData.anchorOffsetY = y; } + public void setAnchorOffsetZ(float z) { this.anchorData.anchorOffsetZ = z; } @Override - public int getAnchorPoint() { return anchorPoint.getId(); } + public int getAnchorPoint() { return anchorData.anchorPoint.getId(); } @Override - public void setAnchorPoint(int point) { this.anchorPoint = AnchorPoint.fromId(point); } + public void setAnchorPoint(int point) { this.anchorData.anchorPoint = AnchorPoint.fromId(point); } @Override @SideOnly(Side.CLIENT) @@ -274,7 +274,7 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { if (npc == null || npc.worldObj == null) return null; EntityAbilityBeam beam = new EntityAbilityBeam(npc.worldObj); - beam.setupPreview(npc, beamWidth, headSize, colorData, lightningData, anchorPoint, windUpTicks, 1.0f); + beam.setupPreview(npc, beamWidth, headSize, colorData, lightningData, anchorData, windUpTicks, 1.0f); return beam; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java index 6c7e8c5b6..014a88f40 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java @@ -6,11 +6,7 @@ import kamkeel.npcs.controllers.data.ability.Ability; import kamkeel.npcs.controllers.data.ability.AnchorPoint; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; -import kamkeel.npcs.controllers.data.ability.data.EnergyColorData; -import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData; -import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData; +import kamkeel.npcs.controllers.data.ability.data.*; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; @@ -19,7 +15,6 @@ import kamkeel.npcs.util.AnchorPointHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.DamageSource; import net.minecraft.util.Vec3; import net.minecraft.world.World; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; @@ -38,15 +33,13 @@ public class AbilityOrb extends Ability implements IAbilityOrb { // Ability-specific properties private float orbSize = 1.0f; - // Anchor point for charging position - private AnchorPoint anchorPoint = AnchorPoint.RIGHT_HAND; - // Data classes for energy properties public final EnergyColorData colorData = new EnergyColorData(); public final EnergyCombatData combatData = new EnergyCombatData(); public final EnergyHomingData homingData = new EnergyHomingData(); public final EnergyLightningData lightningData = new EnergyLightningData(); public final EnergyLifespanData lifespanData = new EnergyLifespanData(); + private EnergyAnchorData anchorData = new EnergyAnchorData(AnchorPoint.RIGHT_HAND); // Transient state for orb entity (used during windup charging) private transient EntityAbilityOrb orbEntity = null; @@ -110,12 +103,12 @@ public class AbilityOrb extends Ability implements IAbilityOrb { // Spawn orb in charging mode on first tick of windup if (tick == 1) { // Create orb in charging mode - follows NPC based on anchor point during windup - Vec3 spawnPos = AnchorPointHelper.calculateAnchorPosition(npc, anchorPoint); + Vec3 spawnPos = AnchorPointHelper.calculateAnchorPosition(npc, anchorData); orbEntity = new EntityAbilityOrb( world, npc, target, spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord, orbSize, colorData, combatData, homingData, lightningData, lifespanData); - orbEntity.setupCharging(anchorPoint, windUpTicks); + orbEntity.setupCharging(anchorData, windUpTicks); orbEntity.setEffects(this.effects); world.spawnEntityInWorld(orbEntity); @@ -175,7 +168,7 @@ public class AbilityOrb extends Ability implements IAbilityOrb { @Override public void writeTypeNBT(NBTTagCompound nbt) { nbt.setFloat("orbSize", orbSize); - nbt.setInteger("anchorPoint", anchorPoint.getId()); + anchorData.writeNBT(nbt); colorData.writeNBT(nbt); combatData.writeNBT(nbt); homingData.writeNBT(nbt); @@ -188,7 +181,7 @@ public class AbilityOrb extends Ability implements IAbilityOrb { @Override public void readTypeNBT(NBTTagCompound nbt) { this.orbSize = nbt.hasKey("orbSize") ? nbt.getFloat("orbSize") : 1.0f; - this.anchorPoint = nbt.hasKey("anchorPoint") ? AnchorPoint.fromId(nbt.getInteger("anchorPoint")) : AnchorPoint.FRONT; + anchorData.readNBT(nbt); colorData.readNBT(nbt); combatData.readNBT(nbt); homingData.readNBT(nbt); @@ -385,21 +378,29 @@ public class AbilityOrb extends Ability implements IAbilityOrb { lightningData.lightningFadeTime = lightningFadeTime; } - public AnchorPoint getAnchorPointEnum() { - return anchorPoint; - } + public AnchorPoint getAnchorPointEnum() { return anchorData.anchorPoint; } - public void setAnchorPointEnum(AnchorPoint anchorPoint) { - this.anchorPoint = anchorPoint; - } + public float getAnchorOffsetX() { return anchorData.anchorOffsetX; } + + public float getAnchorOffsetY() { return anchorData.anchorOffsetY; } + + public float getAnchorOffsetZ() { return anchorData.anchorOffsetZ; } + + public void setAnchorPointEnum(AnchorPoint anchorPoint) { this.anchorData.anchorPoint = anchorPoint; } + + public void setAnchorOffsetX(float x) { this.anchorData.anchorOffsetX = x; } + + public void setAnchorOffsetY(float y) { this.anchorData.anchorOffsetY = y; } + + public void setAnchorOffsetZ(float z) { this.anchorData.anchorOffsetZ = z; } public int getAnchorPoint() { - return anchorPoint.getId(); + return anchorData.anchorPoint.getId(); } @Override public void setAnchorPoint(int point) { - this.anchorPoint = AnchorPoint.fromId(point); + this.anchorData.anchorPoint = AnchorPoint.fromId(point); } @Override @@ -408,7 +409,7 @@ public class AbilityOrb extends Ability implements IAbilityOrb { if (npc == null || npc.worldObj == null) return null; EntityAbilityOrb orb = new EntityAbilityOrb(npc.worldObj); - orb.setupPreview(npc, orbSize, colorData, lightningData, anchorPoint, windUpTicks); + orb.setupPreview(npc, orbSize, colorData, lightningData, anchorData, windUpTicks); return orb; } diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java index ca600b84f..75fa6ef7d 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java @@ -1,11 +1,7 @@ package kamkeel.npcs.entity; import kamkeel.npcs.controllers.data.ability.AnchorPoint; -import kamkeel.npcs.controllers.data.ability.data.EnergyColorData; -import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData; -import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData; +import kamkeel.npcs.controllers.data.ability.data.*; import kamkeel.npcs.util.AnchorPointHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -62,7 +58,7 @@ public class EntityAbilityBeam extends EntityAbilityProjectile { private int chargeDuration = 40; private int chargeTick = 0; private float chargeOffsetDistance = 1.0f; - private AnchorPoint anchorPoint = AnchorPoint.FRONT; + private EnergyAnchorData anchorData = new EnergyAnchorData(AnchorPoint.FRONT); // Trail fading for non-anchored beams (comet effect) private boolean fadeTrail = false; @@ -171,19 +167,19 @@ public class EntityAbilityBeam extends EntityAbilityProjectile { } } - public void setupCharging(AnchorPoint anchorPoint, int chargeDuration, float chargeOffsetDistance) { + public void setupCharging(EnergyAnchorData anchor, int chargeDuration, float chargeOffsetDistance) { setCharging(true); this.chargeDuration = chargeDuration; this.chargeTick = 0; this.chargeOffsetDistance = chargeOffsetDistance; - this.anchorPoint = anchorPoint; + this.anchorData = anchor; this.fadeTrail = !attachedToOwner; this.motionX = 0; this.motionY = 0; this.motionZ = 0; } - public void setupPreview(EntityNPCInterface owner, float beamWidth, float headSize, EnergyColorData color, EnergyLightningData lightning, AnchorPoint anchorPoint, int chargeDuration, float chargeOffsetDistance) { + public void setupPreview(EntityNPCInterface owner, float beamWidth, float headSize, EnergyColorData color, EnergyLightningData lightning, EnergyAnchorData anchor, int chargeDuration, float chargeOffsetDistance) { this.setPreviewMode(true); this.setPreviewOwner(owner); @@ -206,10 +202,10 @@ public class EntityAbilityBeam extends EntityAbilityProjectile { this.chargeDuration = chargeDuration; this.chargeTick = 0; this.chargeOffsetDistance = chargeOffsetDistance; - this.anchorPoint = anchorPoint; + this.anchorData = anchor; // Initial position at anchor point - Vec3 pos = AnchorPointHelper.calculateAnchorPosition(owner, anchorPoint, chargeOffsetDistance); + Vec3 pos = AnchorPointHelper.calculateAnchorPosition(owner, anchorData, chargeOffsetDistance); this.setPosition(pos.xCoord, pos.yCoord, pos.zCoord); this.prevPosX = pos.xCoord; this.prevPosY = pos.yCoord; @@ -450,7 +446,7 @@ public class EntityAbilityBeam extends EntityAbilityProjectile { // Calculate position based on anchor point Vec3 pos; if (owner instanceof EntityLivingBase) { - pos = AnchorPointHelper.calculateAnchorPosition((EntityLivingBase) owner, anchorPoint, chargeOffsetDistance); + pos = AnchorPointHelper.calculateAnchorPosition((EntityLivingBase) owner, anchorData, chargeOffsetDistance); } else { // Fallback for non-living entities (shouldn't happen normally) float yaw = (float) Math.toRadians(owner.rotationYaw); @@ -772,10 +768,11 @@ public class EntityAbilityBeam extends EntityAbilityProjectile { this.chargeDuration = nbt.hasKey("ChargeDuration") ? nbt.getInteger("ChargeDuration") : 40; this.chargeTick = nbt.hasKey("ChargeTick") ? nbt.getInteger("ChargeTick") : 0; this.chargeOffsetDistance = nbt.hasKey("ChargeOffsetDistance") ? nbt.getFloat("ChargeOffsetDistance") : 1.0f; - this.anchorPoint = nbt.hasKey("AnchorPoint") ? AnchorPoint.fromId(nbt.getInteger("AnchorPoint")) : AnchorPoint.FRONT; this.fadeTrail = nbt.hasKey("FadeTrail") && nbt.getBoolean("FadeTrail"); this.trailFadeTime = nbt.hasKey("TrailFadeTime") ? nbt.getInteger("TrailFadeTime") : 20; + this.anchorData.readNBT(nbt); + // Read trail points (relative to origin) trailPoints.clear(); if (nbt.hasKey("Trail")) { @@ -808,10 +805,11 @@ public class EntityAbilityBeam extends EntityAbilityProjectile { nbt.setInteger("ChargeDuration", chargeDuration); nbt.setInteger("ChargeTick", chargeTick); nbt.setFloat("ChargeOffsetDistance", chargeOffsetDistance); - nbt.setInteger("AnchorPoint", anchorPoint.getId()); nbt.setBoolean("FadeTrail", fadeTrail); nbt.setInteger("TrailFadeTime", trailFadeTime); + this.anchorData.writeNBT(nbt); + // Write trail points NBTTagList trailList = new NBTTagList(); for (Vec3 point : trailPoints) { diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java index 20a43a98a..f6003df80 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java @@ -1,11 +1,7 @@ package kamkeel.npcs.entity; import kamkeel.npcs.controllers.data.ability.AnchorPoint; -import kamkeel.npcs.controllers.data.ability.data.EnergyColorData; -import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData; -import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData; +import kamkeel.npcs.controllers.data.ability.data.*; import kamkeel.npcs.util.AnchorPointHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -46,9 +42,9 @@ public class EntityAbilityDisc extends EntityAbilityProjectile { private boolean charging = false; private int chargeDuration = 40; private int chargeTick = 0; - private AnchorPoint anchorPoint = AnchorPoint.FRONT; private float targetDiscRadius = 1.0f; // Full radius to grow to during charging private float targetDiscThickness = 0.2f; // Full thickness to grow to during charging + private EnergyAnchorData anchorData = new EnergyAnchorData(); // Data watcher index for charging state (synced to clients) private static final int DW_CHARGING = 20; @@ -137,11 +133,11 @@ public class EntityAbilityDisc extends EntityAbilityProjectile { * The disc will grow from 0 to discRadius over chargeDuration ticks. * Position follows the owner based on anchor point. */ - public void setupCharging(AnchorPoint anchorPoint, int chargeDuration) { + public void setupCharging(EnergyAnchorData anchor, int chargeDuration) { setCharging(true); this.chargeDuration = chargeDuration; this.chargeTick = 0; - this.anchorPoint = anchorPoint; + this.anchorData = anchor; this.targetDiscRadius = this.discRadius; this.targetDiscThickness = this.discThickness; this.discRadius = 0.01f; @@ -159,7 +155,7 @@ public class EntityAbilityDisc extends EntityAbilityProjectile { * Follows anchor point and animations like in the real game. * Can be fired when transitioning to active phase. */ - public void setupPreview(EntityNPCInterface owner, float discRadius, float discThickness, EnergyColorData color, EnergyLightningData lightning, AnchorPoint anchorPoint, int chargeDuration) { + public void setupPreview(EntityNPCInterface owner, float discRadius, float discThickness, EnergyColorData color, EnergyLightningData lightning, EnergyAnchorData anchor, int chargeDuration) { this.setPreviewMode(true); this.setPreviewOwner(owner); @@ -177,7 +173,7 @@ public class EntityAbilityDisc extends EntityAbilityProjectile { this.setCharging(true); this.chargeDuration = chargeDuration; this.chargeTick = 0; - this.anchorPoint = anchorPoint; + this.anchorData = anchor; // Store target size and start at 0 for grow effect this.targetDiscRadius = discRadius; @@ -187,7 +183,7 @@ public class EntityAbilityDisc extends EntityAbilityProjectile { this.size = 0.01f; // Initial position at anchor point - Vec3 pos = AnchorPointHelper.calculateAnchorPosition(owner, anchorPoint); + Vec3 pos = AnchorPointHelper.calculateAnchorPosition(owner, anchorData); this.setPosition(pos.xCoord, pos.yCoord, pos.zCoord); this.prevPosX = pos.xCoord; this.prevPosY = pos.yCoord; @@ -518,7 +514,7 @@ public class EntityAbilityDisc extends EntityAbilityProjectile { // Calculate position based on anchor point if (owner instanceof EntityLivingBase) { - Vec3 pos = AnchorPointHelper.calculateAnchorPosition((EntityLivingBase) owner, anchorPoint); + Vec3 pos = AnchorPointHelper.calculateAnchorPosition((EntityLivingBase) owner, anchorData); setPosition(pos.xCoord, pos.yCoord, pos.zCoord); } @@ -589,9 +585,9 @@ public class EntityAbilityDisc extends EntityAbilityProjectile { this.dataWatcher.updateObject(DW_CHARGING, (byte) (isCharging ? 1 : 0)); this.chargeDuration = nbt.hasKey("ChargeDuration") ? nbt.getInteger("ChargeDuration") : 40; this.chargeTick = nbt.hasKey("ChargeTick") ? nbt.getInteger("ChargeTick") : 0; - this.anchorPoint = nbt.hasKey("AnchorPoint") ? AnchorPoint.fromId(nbt.getInteger("AnchorPoint")) : AnchorPoint.FRONT; this.targetDiscRadius = nbt.hasKey("TargetDiscRadius") ? nbt.getFloat("TargetDiscRadius") : this.discRadius; this.targetDiscThickness = nbt.hasKey("TargetDiscThickness") ? nbt.getFloat("TargetDiscThickness") : this.discThickness; + this.anchorData.readNBT(nbt); } @Override @@ -609,8 +605,10 @@ public class EntityAbilityDisc extends EntityAbilityProjectile { nbt.setBoolean("Charging", isCharging()); nbt.setInteger("ChargeDuration", chargeDuration); nbt.setInteger("ChargeTick", chargeTick); - nbt.setInteger("AnchorPoint", anchorPoint.getId()); nbt.setFloat("TargetDiscRadius", targetDiscRadius); nbt.setFloat("TargetDiscThickness", targetDiscThickness); + + // Anchor data + this.anchorData.writeNBT(nbt); } } diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityOrb.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityOrb.java index 2473730c3..eff147448 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityOrb.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityOrb.java @@ -1,11 +1,7 @@ package kamkeel.npcs.entity; import kamkeel.npcs.controllers.data.ability.AnchorPoint; -import kamkeel.npcs.controllers.data.ability.data.EnergyColorData; -import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData; -import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData; -import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData; +import kamkeel.npcs.controllers.data.ability.data.*; import kamkeel.npcs.util.AnchorPointHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -36,7 +32,7 @@ public class EntityAbilityOrb extends EntityAbilityProjectile { private boolean charging = false; private int chargeDuration = 40; private int chargeTick = 0; - private AnchorPoint anchorPoint = AnchorPoint.FRONT; + private EnergyAnchorData anchorData = new EnergyAnchorData(AnchorPoint.FRONT); private float targetSize = 1.0f; // Full size to grow to during charging // Data watcher index for charging state (synced to clients) @@ -119,11 +115,11 @@ public class EntityAbilityOrb extends EntityAbilityProjectile { * The orb will grow from 0 to orbSize over chargeDuration ticks. * Position follows the owner based on anchor point. */ - public void setupCharging(AnchorPoint anchorPoint, int chargeDuration) { + public void setupCharging(EnergyAnchorData anchor, int chargeDuration) { setCharging(true); this.chargeDuration = chargeDuration; this.chargeTick = 0; - this.anchorPoint = anchorPoint; + this.anchorData = anchor; this.targetSize = this.size; this.size = 0.01f; this.renderCurrentSize = 0.01f; @@ -138,7 +134,7 @@ public class EntityAbilityOrb extends EntityAbilityProjectile { * Follows anchor point and animations like in the real game. * Can be fired when transitioning to active phase. */ - public void setupPreview(EntityNPCInterface owner, float orbSize, EnergyColorData color, EnergyLightningData lightning, AnchorPoint anchorPoint, int chargeDuration) { + public void setupPreview(EntityNPCInterface owner, float orbSize, EnergyColorData color, EnergyLightningData lightning, EnergyAnchorData anchor, int chargeDuration) { this.setPreviewMode(true); this.setPreviewOwner(owner); @@ -157,7 +153,7 @@ public class EntityAbilityOrb extends EntityAbilityProjectile { this.setCharging(true); this.chargeDuration = chargeDuration; this.chargeTick = 0; - this.anchorPoint = anchorPoint; + this.anchorData = anchor; // Store target size and start at 0 for grow effect this.targetSize = orbSize; @@ -166,7 +162,7 @@ public class EntityAbilityOrb extends EntityAbilityProjectile { this.prevRenderSize = 0.01f; // Initial position at anchor point - Vec3 pos = AnchorPointHelper.calculateAnchorPosition(owner, anchorPoint); + Vec3 pos = AnchorPointHelper.calculateAnchorPosition(owner, anchorData); this.setPosition(pos.xCoord, pos.yCoord, pos.zCoord); this.prevPosX = pos.xCoord; this.prevPosY = pos.yCoord; @@ -400,7 +396,7 @@ public class EntityAbilityOrb extends EntityAbilityProjectile { // Calculate position based on anchor point if (owner instanceof EntityLivingBase) { - Vec3 pos = AnchorPointHelper.calculateAnchorPosition((EntityLivingBase) owner, anchorPoint); + Vec3 pos = AnchorPointHelper.calculateAnchorPosition((EntityLivingBase) owner, anchorData); setPosition(pos.xCoord, pos.yCoord, pos.zCoord); } } @@ -460,8 +456,9 @@ public class EntityAbilityOrb extends EntityAbilityProjectile { this.dataWatcher.updateObject(DW_CHARGING, (byte) (isCharging ? 1 : 0)); this.chargeDuration = nbt.hasKey("ChargeDuration") ? nbt.getInteger("ChargeDuration") : 40; this.chargeTick = nbt.hasKey("ChargeTick") ? nbt.getInteger("ChargeTick") : 0; - this.anchorPoint = nbt.hasKey("AnchorPoint") ? AnchorPoint.fromId(nbt.getInteger("AnchorPoint")) : AnchorPoint.FRONT; this.targetSize = nbt.hasKey("TargetSize") ? nbt.getFloat("TargetSize") : this.size; + // Anchor data + this.anchorData.readNBT(nbt); } @Override @@ -474,7 +471,7 @@ public class EntityAbilityOrb extends EntityAbilityProjectile { nbt.setBoolean("Charging", isCharging()); nbt.setInteger("ChargeDuration", chargeDuration); nbt.setInteger("ChargeTick", chargeTick); - nbt.setInteger("AnchorPoint", anchorPoint.getId()); + anchorData.writeNBT(nbt); nbt.setFloat("TargetSize", targetSize); } } diff --git a/src/main/java/kamkeel/npcs/util/AnchorPointHelper.java b/src/main/java/kamkeel/npcs/util/AnchorPointHelper.java index 45e4f3eab..d9d584b64 100644 --- a/src/main/java/kamkeel/npcs/util/AnchorPointHelper.java +++ b/src/main/java/kamkeel/npcs/util/AnchorPointHelper.java @@ -1,6 +1,7 @@ package kamkeel.npcs.util; import kamkeel.npcs.controllers.data.ability.AnchorPoint; +import kamkeel.npcs.controllers.data.ability.data.EnergyAnchorData; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.Vec3; import noppes.npcs.constants.EnumAnimationPart; @@ -48,17 +49,23 @@ public class AnchorPointHelper { /** * Calculate world position for an anchor point on an entity. */ - public static Vec3 calculateAnchorPosition(EntityLivingBase entity, AnchorPoint anchor) { - return calculateAnchorPosition(entity, anchor, DEFAULT_FRONT_DISTANCE); + public static Vec3 calculateAnchorPosition(EntityLivingBase entity, EnergyAnchorData anchorData) { + return calculateAnchorPosition(entity, anchorData, DEFAULT_FRONT_DISTANCE); } /** * Calculate world position for an anchor point with custom front offset. */ - public static Vec3 calculateAnchorPosition(EntityLivingBase entity, AnchorPoint anchor, float frontOffset) { + public static Vec3 calculateAnchorPosition(EntityLivingBase entity, EnergyAnchorData anchorData, float frontOffset) { float scale = getModelScale(entity); float height = entity.height; + AnchorPoint anchor = anchorData.anchorPoint; + + float anchorX = anchorData.anchorOffsetX; + float anchorY = anchorData.anchorOffsetY; + float anchorZ = anchorData.anchorOffsetZ; + double x = entity.posX; double y = entity.posY; double z = entity.posZ; @@ -78,10 +85,10 @@ public class AnchorPointHelper { break; case RIGHT_HAND: - return calculateHandPosition(entity, true, scale); + return calculateHandPosition(entity, anchorData, true, scale); case LEFT_HAND: - return calculateHandPosition(entity, false, scale); + return calculateHandPosition(entity, anchorData, false, scale); case ABOVE_HEAD: y += height * ABOVE_HEAD_HEIGHT; @@ -92,6 +99,10 @@ public class AnchorPointHelper { break; } + x += anchorX * scale; + y += anchorY * scale; + z += anchorZ * scale; + return Vec3.createVectorHelper(x, y, z); } @@ -124,22 +135,22 @@ public class AnchorPointHelper { /** * Calculate hand position using animation data if available. */ - private static Vec3 calculateHandPosition(EntityLivingBase entity, boolean rightHand, float scale) { + private static Vec3 calculateHandPosition(EntityLivingBase entity, EnergyAnchorData anchor, boolean rightHand, float scale) { // Try to get animated position first - Vec3 animatedPos = getAnimatedHandPosition(entity, rightHand, scale); + Vec3 animatedPos = getAnimatedHandPosition(entity, anchor, rightHand, scale); if (animatedPos != null) { return animatedPos; } // Fallback to static position - return calculateFallbackHandPosition(entity, rightHand, scale); + return calculateFallbackHandPosition(entity, anchor, rightHand, scale); } /** * Calculate hand position from animation data. * Works for both NPCs and Players. */ - private static Vec3 getAnimatedHandPosition(EntityLivingBase entity, boolean rightHand, float scale) { + private static Vec3 getAnimatedHandPosition(EntityLivingBase entity, EnergyAnchorData anchor, boolean rightHand, float scale) { AnimationData animData = AnimationData.getData(entity); if (animData == null || !animData.isActive() || animData.animation == null) { return null; @@ -235,6 +246,10 @@ public class AnchorPointHelper { double worldY = entity.posY + shoulderHeight - blockY; double worldZ = entity.posZ + worldOffsetZ; + worldX += anchor.anchorOffsetX * scale; + worldY += anchor.anchorOffsetY * scale; + worldZ += anchor.anchorOffsetZ * scale; + return Vec3.createVectorHelper(worldX, worldY, worldZ); } @@ -277,7 +292,7 @@ public class AnchorPointHelper { * Calculate fallback hand position when no animation is active. * Represents arms hanging at sides in default idle pose. */ - private static Vec3 calculateFallbackHandPosition(EntityLivingBase entity, boolean rightHand, float scale) { + private static Vec3 calculateFallbackHandPosition(EntityLivingBase entity, EnergyAnchorData anchor, boolean rightHand, float scale) { float bodyYaw = (float) Math.toRadians(entity.renderYawOffset); // Get arm scale for EntityCustomNpc @@ -302,6 +317,10 @@ public class AnchorPointHelper { double y = entity.posY + entity.height * FALLBACK_ARM_HEIGHT + armLengthOffset; double z = entity.posZ + lateralZ + forwardZ; + x += anchor.anchorOffsetX * scale; + y += anchor.anchorOffsetY * scale; + z += anchor.anchorOffsetZ * scale; + return Vec3.createVectorHelper(x, y, z); }