From 43bb61e070ad649ce4ed2f1a49fe0ec47e00db2e Mon Sep 17 00:00:00 2001 From: Vidal Date: Sun, 11 Jan 2026 17:42:08 -0300 Subject: [PATCH] Implemented compatibility to players --- src/api | 2 +- .../controllers/data/ability/Ability.java | 74 ++++--- .../controllers/data/ability/Condition.java | 24 ++- .../data/ability/type/AbilityBeam.java | 32 +-- .../data/ability/type/AbilityCharge.java | 126 ++++++----- .../data/ability/type/AbilityCutter.java | 46 ++-- .../data/ability/type/AbilityDash.java | 61 +++--- .../data/ability/type/AbilityGuard.java | 9 +- .../data/ability/type/AbilityHazard.java | 85 ++++---- .../data/ability/type/AbilityHeal.java | 37 ++-- .../data/ability/type/AbilityHeavyHit.java | 7 +- .../data/ability/type/AbilityOrb.java | 42 ++-- .../data/ability/type/AbilityProjectile.java | 35 +-- .../data/ability/type/AbilityShockwave.java | 32 +-- .../data/ability/type/AbilitySlam.java | 163 ++++++++------ .../data/ability/type/AbilityTeleport.java | 87 ++++---- .../data/ability/type/AbilityTrap.java | 95 ++++---- .../data/ability/type/AbilityVortex.java | 44 ++-- .../kamkeel/npcs/network/PacketHandler.java | 6 +- .../npcs/network/enums/EnumRequestPacket.java | 2 + .../ability/AbilitiesPlayerGetPacket.java | 50 +++++ .../ability/AbilitiesPlayerSavePacket.java | 65 ++++++ src/main/java/noppes/npcs/DataAbilities.java | 203 +++++++++++++----- .../npcs/controllers/data/PlayerData.java | 13 +- .../npcs/entity/EntityNPCInterface.java | 11 +- .../npcs/scripted/event/AbilityEvent.java | 38 ++-- 26 files changed, 864 insertions(+), 525 deletions(-) create mode 100644 src/main/java/kamkeel/npcs/network/packets/request/ability/AbilitiesPlayerGetPacket.java create mode 100644 src/main/java/kamkeel/npcs/network/packets/request/ability/AbilitiesPlayerSavePacket.java diff --git a/src/api b/src/api index 5cd088851..0eae6c5cf 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit 5cd0888511c6ab16fa454919c6269e4013bbc965 +Subproject commit 0eae6c5cfd970da4c61559048b0f5851283b326f diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java index b6c392b5c..2e8617c2b 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -6,6 +6,7 @@ import kamkeel.npcs.controllers.data.ability.telegraph.TelegraphInstance; import kamkeel.npcs.controllers.data.ability.telegraph.TelegraphType; import net.minecraft.block.Block; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -15,6 +16,7 @@ import noppes.npcs.NpcDamageSource; import noppes.npcs.api.INbt; import noppes.npcs.api.ability.IAbility; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.entity.EntityNPCInterface; @@ -90,10 +92,10 @@ public abstract class Ability implements IAbility { // ═══════════════════════════════════════════════════════════════════ /** Called first tick of ACTIVE phase */ - public abstract void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world); + public abstract void onExecute(IAbilityHolder entity, EntityLivingBase target, World world); /** Called every tick of ACTIVE phase */ - public abstract void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick); + public abstract void onActiveTick(IAbilityHolder entity, EntityLivingBase target, World world, int tick); /** Write type-specific config to NBT */ public abstract void writeTypeNBT(NBTTagCompound nbt); @@ -105,24 +107,24 @@ public abstract class Ability implements IAbility { // OPTIONAL OVERRIDES // ═══════════════════════════════════════════════════════════════════ - public void onWindUpTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) {} - public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) {} - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) {} + public void onWindUpTick(IAbilityHolder entity, EntityLivingBase target, World world, int tick) {} + public void onInterrupt(IAbilityHolder entity, DamageSource source, float damage) {} + public void onComplete(IAbilityHolder entity, EntityLivingBase target) {} /** * Apply damage to an entity with ability hit event support. * Fires the abilityHit script event, allowing scripts to modify or cancel the damage. * - * @param npc The NPC executing the ability + * @param holder The entity executing the ability * @param hitEntity The entity being hit * @param damage The damage amount * @param knockback The horizontal knockback * @param knockbackUp The vertical knockback * @return true if damage was applied (not cancelled), false if cancelled */ - protected boolean applyAbilityDamage(EntityNPCInterface npc, EntityLivingBase hitEntity, + protected boolean applyAbilityDamage(IAbilityHolder holder, EntityLivingBase hitEntity, float damage, float knockback, float knockbackUp) { - DataAbilities dataAbilities = npc.abilities; + DataAbilities dataAbilities = (DataAbilities) holder.getAbilityData(); AbilityEvent.HitEvent event = dataAbilities.fireHitEvent( this, currentTarget, hitEntity, damage, knockback, knockbackUp); @@ -137,13 +139,14 @@ protected boolean applyAbilityDamage(EntityNPCInterface npc, EntityLivingBase hi // Apply damage if (finalDamage > 0) { - hitEntity.attackEntityFrom(new NpcDamageSource("mob", npc), finalDamage); + hitEntity.attackEntityFrom(new NpcDamageSource("mob", dataAbilities.getEntity()), finalDamage); } // Apply knockback if any if (finalKnockback > 0 || finalKnockbackUp > 0) { - double dx = hitEntity.posX - npc.posX; - double dz = hitEntity.posZ - npc.posZ; + + double dx = hitEntity.posX - dataAbilities.getEntity().posX; + double dz = hitEntity.posZ - dataAbilities.getEntity().posZ; double len = Math.sqrt(dx * dx + dz * dz); if (len > 0 && finalKnockback > 0) { dx /= len; @@ -162,7 +165,7 @@ protected boolean applyAbilityDamage(EntityNPCInterface npc, EntityLivingBase hi * Apply damage to an entity with ability hit event support and custom knockback direction. * Fires the abilityHit script event, allowing scripts to modify or cancel the damage. * - * @param npc The NPC executing the ability + * @param holder The entity executing the ability * @param hitEntity The entity being hit * @param damage The damage amount * @param knockback The horizontal knockback @@ -171,10 +174,10 @@ protected boolean applyAbilityDamage(EntityNPCInterface npc, EntityLivingBase hi * @param knockbackDirZ The Z component of knockback direction (normalized) * @return true if damage was applied (not cancelled), false if cancelled */ - protected boolean applyAbilityDamageWithDirection(EntityNPCInterface npc, EntityLivingBase hitEntity, + protected boolean applyAbilityDamageWithDirection(IAbilityHolder holder, EntityLivingBase hitEntity, float damage, float knockback, float knockbackUp, double knockbackDirX, double knockbackDirZ) { - DataAbilities dataAbilities = npc.abilities; + DataAbilities dataAbilities = (DataAbilities) holder.getAbilityData(); AbilityEvent.HitEvent event = dataAbilities.fireHitEvent( this, currentTarget, hitEntity, damage, knockback, knockbackUp); @@ -189,7 +192,7 @@ protected boolean applyAbilityDamageWithDirection(EntityNPCInterface npc, Entity // Apply damage if (finalDamage > 0) { - hitEntity.attackEntityFrom(DamageSource.causeMobDamage(npc), finalDamage); + hitEntity.attackEntityFrom(DamageSource.causeMobDamage(dataAbilities.getEntity()), finalDamage); } // Apply knockback in specified direction @@ -264,37 +267,38 @@ public SubGuiAbilityConfig createConfigGui(IAbilityConfigCallback callback) { * Create a telegraph instance for this ability. * Override for custom telegraph shapes. * - * @param npc The caster + * @param holder The caster * @param target The target (for position calculation) * @return The telegraph instance, or null if no telegraph */ - public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBase target) { + public TelegraphInstance createTelegraph(IAbilityHolder holder, EntityLivingBase target) { if (!showTelegraph || telegraphType == TelegraphType.NONE) { return null; } + Entity entity = (Entity) holder; Telegraph telegraph; double x, y, z; - float yaw = npc.rotationYaw; + float yaw = entity.rotationYaw; // Determine position based on targeting mode - boolean positionAtNpc = targetingMode == TargetingMode.AOE_SELF || + boolean positionAtEntity = targetingMode == TargetingMode.AOE_SELF || targetingMode == TargetingMode.SELF || telegraphType == TelegraphType.LINE || telegraphType == TelegraphType.CONE; - if (positionAtNpc) { - x = npc.posX; - y = findGroundLevel(npc.worldObj, npc.posX, npc.posY, npc.posZ); - z = npc.posZ; + if (positionAtEntity) { + x = entity.posX; + y = findGroundLevel(entity.worldObj, entity.posX, entity.posY, entity.posZ); + z = entity.posZ; } else if (target != null) { x = target.posX; - y = findGroundLevel(npc.worldObj, target.posX, target.posY, target.posZ); + y = findGroundLevel(entity.worldObj, target.posX, target.posY, target.posZ); z = target.posZ; } else { - x = npc.posX; - y = findGroundLevel(npc.worldObj, npc.posX, npc.posY, npc.posZ); - z = npc.posZ; + x = entity.posX; + y = findGroundLevel(entity.worldObj, entity.posX, entity.posY, entity.posZ); + z = entity.posZ; } // Create telegraph based on type @@ -325,12 +329,12 @@ public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBas telegraph.setHeightOffset(telegraphHeightOffset); TelegraphInstance instance = new TelegraphInstance(telegraph, x, y, z, yaw); - instance.setCasterEntityId(npc.getEntityId()); + instance.setCasterEntityId(entity.getEntityId()); // Set entity to follow based on targeting mode - if (positionAtNpc) { + if (positionAtEntity) { // AOE_SELF abilities: telegraph follows NPC during windup - instance.setEntityIdToFollow(npc.getEntityId()); + instance.setEntityIdToFollow(entity.getEntityId()); } else if (target != null) { // AOE_TARGET abilities: telegraph follows target during windup instance.setEntityIdToFollow(target.getEntityId()); @@ -496,23 +500,23 @@ public void reset() { // CONDITION CHECKING // ═══════════════════════════════════════════════════════════════════ - public boolean checkConditions(EntityNPCInterface npc, EntityLivingBase target) { + public boolean checkConditions(IAbilityHolder holder, EntityLivingBase target) { for (Condition c : conditions) { - if (!c.check(npc, target)) return false; + if (!c.check(holder, target)) return false; } return true; } /** Full eligibility check */ - public boolean canUse(EntityNPCInterface npc, EntityLivingBase target) { + public boolean canUse(IAbilityHolder holder, EntityLivingBase target) { if (!enabled) return false; if (isOnCooldown()) return false; if (isExecuting()) return false; - float distance = npc.getDistanceToEntity(target); + float distance = ((Entity) holder).getDistanceToEntity(target); if (distance < minRange || distance > maxRange) return false; - return checkConditions(npc, target); + return checkConditions(holder, target); } // ═══════════════════════════════════════════════════════════════════ diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Condition.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Condition.java index 70b3b290f..d9dbc7b67 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Condition.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Condition.java @@ -2,6 +2,8 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.DataAbilities; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.entity.EntityNPCInterface; /** @@ -13,11 +15,11 @@ public interface Condition { /** * Check if this condition is met. * - * @param npc The NPC that would use the ability + * @param holder The entity that would use the ability * @param target The current target (may be null for self-targeting abilities) * @return true if the condition is satisfied */ - boolean check(EntityNPCInterface npc, EntityLivingBase target); + boolean check(IAbilityHolder holder, EntityLivingBase target); /** * Get the condition type ID for serialization. @@ -87,8 +89,8 @@ public ConditionHPAbove(float threshold) { } @Override - public boolean check(EntityNPCInterface npc, EntityLivingBase target) { - return npc.getHealth() / npc.getMaxHealth() > threshold; + public boolean check(IAbilityHolder entity, EntityLivingBase target) { + return ((EntityLivingBase) entity).getHealth() / ((EntityLivingBase) entity).getMaxHealth() > threshold; } @Override @@ -121,8 +123,8 @@ public ConditionHPBelow(float threshold) { } @Override - public boolean check(EntityNPCInterface npc, EntityLivingBase target) { - return npc.getHealth() / npc.getMaxHealth() < threshold; + public boolean check(IAbilityHolder entity, EntityLivingBase target) { + return ((EntityLivingBase) entity).getHealth() / ((EntityLivingBase) entity).getMaxHealth() < threshold; } @Override @@ -155,7 +157,7 @@ public ConditionTargetHPAbove(float threshold) { } @Override - public boolean check(EntityNPCInterface npc, EntityLivingBase target) { + public boolean check(IAbilityHolder entity, EntityLivingBase target) { if (target == null) return false; return target.getHealth() / target.getMaxHealth() > threshold; } @@ -190,7 +192,7 @@ public ConditionTargetHPBelow(float threshold) { } @Override - public boolean check(EntityNPCInterface npc, EntityLivingBase target) { + public boolean check(IAbilityHolder entity, EntityLivingBase target) { if (target == null) return false; return target.getHealth() / target.getMaxHealth() < threshold; } @@ -228,10 +230,10 @@ public ConditionHitCount(int requiredHits, int withinTicks) { } @Override - public boolean check(EntityNPCInterface npc, EntityLivingBase target) { + public boolean check(IAbilityHolder entity, EntityLivingBase target) { // Check NPC's recent hit count from DataAbilities - if (npc.abilities != null) { - return npc.abilities.getRecentHitCount(withinTicks) >= requiredHits; + if (entity.getAbilityData() != null) { + return entity.getAbilityData().getRecentHitCount(withinTicks) >= requiredHits; } return false; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java index 2dc67e5c0..5148a4d5a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityBeam; @@ -79,7 +80,7 @@ public TargetingMode[] getAllowedTargetingModes() { } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { // Initialize beam currentSweepAngle = -sweepAngle / 2; sweepingRight = true; @@ -88,9 +89,10 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (world.isRemote) return; + EntityLivingBase entity = (EntityLivingBase) holder; hitThisTick.clear(); ticksSinceDamage++; @@ -117,12 +119,12 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World } // Calculate beam direction - float baseYaw = npc.rotationYaw; + float baseYaw = entity.rotationYaw; // If lock on target, point at target if (lockOnTarget && target != null) { - double dx = target.posX - npc.posX; - double dz = target.posZ - npc.posZ; + double dx = target.posX - entity.posX; + double dz = target.posZ - entity.posZ; baseYaw = (float) Math.toDegrees(Math.atan2(-dx, dz)); } @@ -130,9 +132,9 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World float yawRad = (float) Math.toRadians(beamYaw); // Calculate beam start position - double startX = npc.posX; - double startY = npc.posY + npc.getEyeHeight() * 0.8; - double startZ = npc.posZ; + double startX = entity.posX; + double startY = entity.posY + entity.getEyeHeight() * 0.8; + double startZ = entity.posZ; double dirX = -Math.sin(yawRad); double dirZ = Math.cos(yawRad); @@ -158,18 +160,18 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, checkBox); - for (Entity entity : entities) { - if (!(entity instanceof EntityLivingBase)) continue; - if (entity == npc) continue; - if (hitThisTick.contains(entity.getEntityId())) continue; + for (Entity e : entities) { + if (!(e instanceof EntityLivingBase)) continue; + if (e == entity) continue; + if (hitThisTick.contains(e.getEntityId())) continue; - EntityLivingBase livingEntity = (EntityLivingBase) entity; + EntityLivingBase livingEntity = (EntityLivingBase) e; // Check if actually in beam path if (isInBeamPath(livingEntity, startX, startY, startZ, dirX, dirZ)) { - hitThisTick.add(entity.getEntityId()); + hitThisTick.add(e.getEntityId()); // Apply damage with scripted event support (no knockback for beam) - applyAbilityDamage(npc, livingEntity, damage, 0, 0); + applyAbilityDamage(holder, livingEntity, damage, 0, 0); if (!piercing) { return; // Stop at first hit diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java index f2a88edb6..cc4c6afbb 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java @@ -14,6 +14,7 @@ import net.minecraft.util.DamageSource; import net.minecraft.util.Vec3; import net.minecraft.world.World; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityCharge; @@ -84,108 +85,115 @@ public boolean hasAbilityMovement() { * Called on the first tick of windup - lock direction here so it matches telegraph. */ @Override - public void onWindUpTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onWindUpTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (tick == 1) { // Lock direction on first windup tick (same time telegraph is created) - lockChargeDirection(npc, target); + lockChargeDirection(holder, target); } // Keep NPC facing the locked direction during windup - enforceLockedRotation(npc); + enforceLockedRotation(holder); } /** * Locks the charge direction based on current target position. * Called once at windup start - direction won't change even if target moves. */ - private void lockChargeDirection(EntityNPCInterface npc, EntityLivingBase target) { + private void lockChargeDirection(IAbilityHolder holder, EntityLivingBase target) { + EntityLivingBase entity = (EntityLivingBase) holder; + if (target != null) { - double dx = target.posX - npc.posX; - double dz = target.posZ - npc.posZ; + double dx = target.posX - entity.posX; + double dz = target.posZ - entity.posZ; double len = Math.sqrt(dx * dx + dz * dz); if (len > 0) { chargeDirection = Vec3.createVectorHelper(dx / len, 0, dz / len); } else { - float yaw = (float) Math.toRadians(npc.rotationYaw); + float yaw = (float) Math.toRadians(entity.rotationYaw); chargeDirection = Vec3.createVectorHelper(-Math.sin(yaw), 0, Math.cos(yaw)); } } else { - float yaw = (float) Math.toRadians(npc.rotationYaw); + float yaw = (float) Math.toRadians(entity.rotationYaw); chargeDirection = Vec3.createVectorHelper(-Math.sin(yaw), 0, Math.cos(yaw)); } lockedYaw = (float) Math.toDegrees(Math.atan2(-chargeDirection.xCoord, chargeDirection.zCoord)); } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { + EntityLivingBase entity = (EntityLivingBase) holder; + // Initialize charge - direction was already locked during windup - startX = npc.posX; - startY = npc.posY; - startZ = npc.posZ; + startX = entity.posX; + startY = entity.posY; + startZ = entity.posZ; hitEntities.clear(); // If direction wasn't set during windup (shouldn't happen), set it now if (chargeDirection == null) { - lockChargeDirection(npc, target); + lockChargeDirection(holder, target); } - enforceLockedRotation(npc); + enforceLockedRotation(holder); } - private void enforceLockedRotation(EntityNPCInterface npc) { - npc.rotationYaw = lockedYaw; - npc.rotationYawHead = lockedYaw; - npc.prevRotationYaw = lockedYaw; - npc.prevRotationYawHead = lockedYaw; - npc.renderYawOffset = lockedYaw; - npc.prevRenderYawOffset = lockedYaw; + private void enforceLockedRotation(IAbilityHolder holder) { + EntityLivingBase entity = (EntityLivingBase) holder; + entity.rotationYaw = lockedYaw; + entity.rotationYawHead = lockedYaw; + entity.prevRotationYaw = lockedYaw; + entity.prevRotationYawHead = lockedYaw; + entity.renderYawOffset = lockedYaw; + entity.prevRenderYawOffset = lockedYaw; } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (chargeDirection == null) return; + EntityLivingBase entity = (EntityLivingBase) holder; + // Enforce rotation every tick - enforceLockedRotation(npc); + enforceLockedRotation(holder); // Calculate distance traveled double distanceTraveled = Math.sqrt( - Math.pow(npc.posX - startX, 2) + - Math.pow(npc.posZ - startZ, 2) + Math.pow(entity.posX - startX, 2) + + Math.pow(entity.posZ - startZ, 2) ); // Check if reached max distance if (distanceTraveled >= maxDistance) { - npc.motionX = 0; - npc.motionZ = 0; - npc.velocityChanged = true; + entity.motionX = 0; + entity.motionZ = 0; + entity.velocityChanged = true; return; } // Move NPC - npc.motionX = chargeDirection.xCoord * chargeSpeed; - npc.motionY = 0; - npc.motionZ = chargeDirection.zCoord * chargeSpeed; - npc.velocityChanged = true; + entity.motionX = chargeDirection.xCoord * chargeSpeed; + entity.motionY = 0; + entity.motionZ = chargeDirection.zCoord * chargeSpeed; + entity.velocityChanged = true; // Server-side collision damage if (!world.isRemote) { - AxisAlignedBB hitBox = npc.boundingBox.expand(hitRadius, hitRadius * 0.5, hitRadius); + AxisAlignedBB hitBox = entity.boundingBox.expand(hitRadius, hitRadius * 0.5, hitRadius); @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, hitBox); - for (Entity entity : entities) { - if (!(entity instanceof EntityLivingBase)) continue; - if (entity == npc) continue; - if (hitEntities.contains(entity.getEntityId())) continue; + for (Entity e : entities) { + if (!(e instanceof EntityLivingBase)) continue; + if (e == entity) continue; + if (hitEntities.contains(e.getEntityId())) continue; - EntityLivingBase livingEntity = (EntityLivingBase) entity; + EntityLivingBase livingEntity = (EntityLivingBase) e; - // Hit this entity + // Hit this e hitEntities.add(entity.getEntityId()); // Apply damage with scripted event support - boolean wasHit = applyAbilityDamageWithDirection(npc, livingEntity, damage, knockback, knockbackUp, + boolean wasHit = applyAbilityDamageWithDirection(holder, livingEntity, damage, knockback, knockbackUp, chargeDirection.xCoord, chargeDirection.zCoord); // Play impact sound if hit wasn't cancelled @@ -197,21 +205,22 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { - stopMomentum(npc); - super.onComplete(npc, target); + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { + stopMomentum(holder); + super.onComplete(holder, target); } @Override - public void onInterrupt(EntityNPCInterface npc, net.minecraft.util.DamageSource source, float damage) { - stopMomentum(npc); - super.onInterrupt(npc, source, damage); + public void onInterrupt(IAbilityHolder holder, net.minecraft.util.DamageSource source, float damage) { + stopMomentum(holder); + super.onInterrupt(holder, source, damage); } - private void stopMomentum(EntityNPCInterface npc) { - npc.motionX = 0; - npc.motionZ = 0; - npc.velocityChanged = true; + private void stopMomentum(IAbilityHolder holder) { + EntityLivingBase entity = (EntityLivingBase) holder; + entity.motionX = 0; + entity.motionZ = 0; + entity.velocityChanged = true; } @Override @@ -237,19 +246,20 @@ public float getTelegraphWidth() { * Direction is locked at creation based on target position. */ @Override - public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBase target) { + public TelegraphInstance createTelegraph(IAbilityHolder holder, EntityLivingBase target) { if (!isShowTelegraph() || getTelegraphType() == TelegraphType.NONE) { return null; } + EntityLivingBase entity = (EntityLivingBase) holder; // Calculate direction to target at this moment (locked) float yaw; if (target != null) { - double dx = target.posX - npc.posX; - double dz = target.posZ - npc.posZ; + double dx = target.posX - entity.posX; + double dz = target.posZ - entity.posZ; yaw = (float) Math.toDegrees(Math.atan2(-dx, dz)); } else { - yaw = npc.rotationYaw; + yaw = entity.rotationYaw; } // Create LINE telegraph @@ -261,11 +271,11 @@ public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBas telegraph.setHeightOffset(telegraphHeightOffset); // Position at NPC ground level, direction towards target - double groundY = findGroundLevel(npc.worldObj, npc.posX, npc.posY, npc.posZ); - TelegraphInstance instance = new TelegraphInstance(telegraph, npc.posX, groundY, npc.posZ, yaw); - instance.setCasterEntityId(npc.getEntityId()); + double groundY = findGroundLevel(entity.worldObj, entity.posX, entity.posY, entity.posZ); + TelegraphInstance instance = new TelegraphInstance(telegraph, entity.posX, groundY, entity.posZ, yaw); + instance.setCasterEntityId(entity.getEntityId()); // Telegraph follows NPC during windup - allows NPC to reposition - instance.setEntityIdToFollow(npc.getEntityId()); + instance.setEntityIdToFollow(entity.getEntityId()); return instance; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java index 5e81501a9..7bb079960 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java @@ -12,6 +12,7 @@ import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.DamageSource; import net.minecraft.world.World; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityCutter; @@ -97,18 +98,18 @@ public TargetingMode[] getAllowedTargetingModes() { public float getTelegraphAngle() { return arcAngle; } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { hitEntities.clear(); currentWave = 0; currentRotation = startAngleOffset; if (sweepMode == SweepMode.INSTANT && !world.isRemote) { - performSweepDamage(npc, world, 0.0f, range); + performSweepDamage(holder, world, 0.0f, range); } } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (world.isRemote) return; switch (sweepMode) { @@ -117,7 +118,7 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World float waveProgress = (float)(currentWave + 1) / sweepWaves; float waveInner = innerRadius + (range - innerRadius) * ((float)currentWave / sweepWaves); float waveOuter = innerRadius + (range - innerRadius) * waveProgress; - performSweepDamage(npc, world, waveInner, waveOuter); + performSweepDamage(holder, world, waveInner, waveOuter); currentWave++; } break; @@ -125,7 +126,7 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World case ROTATING: currentRotation += rotationSpeed; hitEntities.clear(); - performSweepDamage(npc, world, innerRadius, range); + performSweepDamage(holder, world, innerRadius, range); break; case INSTANT: @@ -133,46 +134,47 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World } } - private void performSweepDamage(EntityNPCInterface npc, World world, float minDist, float maxDist) { - float casterYaw = npc.rotationYaw + currentRotation; + private void performSweepDamage(IAbilityHolder holder, World world, float minDist, float maxDist) { + EntityLivingBase entity = (EntityLivingBase) holder; + float casterYaw = entity.rotationYaw + currentRotation; AxisAlignedBB searchBox = AxisAlignedBB.getBoundingBox( - npc.posX - maxDist, npc.posY - 1, npc.posZ - maxDist, - npc.posX + maxDist, npc.posY + 3, npc.posZ + maxDist + entity.posX - maxDist, entity.posY - 1, entity.posZ - maxDist, + entity.posX + maxDist, entity.posY + 3, entity.posZ + maxDist ); @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, searchBox); - for (EntityLivingBase entity : entities) { - if (entity == npc) continue; - if (hitEntities.contains(entity.getEntityId())) continue; - // If not piercing, stop after hitting one entity this sweep + for (EntityLivingBase currentEntity : entities) { + if (currentEntity == entity) continue; + if (hitEntities.contains(currentEntity.getEntityId())) continue; + // If not piercing, stop after hitting one e this sweep if (!piercing && !hitEntities.isEmpty()) break; - double dx = entity.posX - npc.posX; - double dz = entity.posZ - npc.posZ; + double dx = currentEntity.posX - entity.posX; + double dz = currentEntity.posZ - entity.posZ; double dist = Math.sqrt(dx * dx + dz * dz); if (dist < minDist || dist > maxDist) continue; if (!isInArc(dx, dz, casterYaw, arcAngle)) continue; - hitEntities.add(entity.getEntityId()); + hitEntities.add(currentEntity.getEntityId()); float distFactor = 1.0f - ((float)dist / maxDist) * 0.3f; float actualDamage = damage * distFactor; // Apply damage with scripted event support - boolean wasHit = applyAbilityDamage(npc, entity, actualDamage, knockback, knockbackUp); + boolean wasHit = applyAbilityDamage(holder, currentEntity, actualDamage, knockback, knockbackUp); // Only apply effects if hit wasn't cancelled if (wasHit) { if (stunDuration > 0) { - entity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunDuration, 10)); - entity.addPotionEffect(new PotionEffect(Potion.weakness.id, stunDuration, 2)); + currentEntity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunDuration, 10)); + currentEntity.addPotionEffect(new PotionEffect(Potion.weakness.id, stunDuration, 2)); } if (bleedDuration > 0) { - entity.addPotionEffect(new PotionEffect(Potion.wither.id, bleedDuration, bleedLevel)); + currentEntity.addPotionEffect(new PotionEffect(Potion.wither.id, bleedDuration, bleedLevel)); } } } @@ -191,14 +193,14 @@ private double normalizeAngle(double angle) { } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { hitEntities.clear(); currentWave = 0; currentRotation = startAngleOffset; } @Override - public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) { + public void onInterrupt(IAbilityHolder holder, DamageSource source, float damage) { hitEntities.clear(); currentWave = 0; currentRotation = startAngleOffset; diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java index 920e57f96..a0c7fcbcc 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java @@ -4,6 +4,8 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; +import net.minecraft.util.DamageSource; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityDash; @@ -121,10 +123,11 @@ public boolean hasAbilityMovement() { } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { - startX = npc.posX; - startY = npc.posY; - startZ = npc.posZ; + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { + EntityLivingBase entity = (EntityLivingBase) holder; + startX = entity.posX; + startY = entity.posY; + startZ = entity.posZ; // Choose random direction based on mode DashDirection[] directions = dashMode == DashMode.AGGRESSIVE @@ -135,11 +138,11 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor // Calculate dash direction relative to target float baseYaw; if (target != null) { - double dx = target.posX - npc.posX; - double dz = target.posZ - npc.posZ; + double dx = target.posX - entity.posX; + double dz = target.posZ - entity.posZ; baseYaw = (float) Math.toDegrees(Math.atan2(-dx, dz)); } else { - baseYaw = npc.rotationYaw; + baseYaw = entity.rotationYaw; } // Apply direction offset @@ -153,51 +156,55 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor ); // Play dash sound - world.playSoundAtEntity(npc, "mob.endermen.portal", 0.5f, 1.5f); + world.playSoundAtEntity(entity, "mob.endermen.portal", 0.5f, 1.5f); } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (dashDirection == null) return; + EntityLivingBase entity = (EntityLivingBase) holder; + // Calculate distance traveled double distanceTraveled = Math.sqrt( - Math.pow(npc.posX - startX, 2) + - Math.pow(npc.posZ - startZ, 2) + Math.pow(entity.posX - startX, 2) + + Math.pow(entity.posZ - startZ, 2) ); // Check if reached max distance if (distanceTraveled >= dashDistance) { - npc.motionX = 0; - npc.motionZ = 0; - npc.velocityChanged = true; + entity.motionX = 0; + entity.motionZ = 0; + entity.velocityChanged = true; return; } // Move NPC - npc.motionX = dashDirection.xCoord * dashSpeed; - npc.motionY = 0; - npc.motionZ = dashDirection.zCoord * dashSpeed; - npc.velocityChanged = true; + entity.motionX = dashDirection.xCoord * dashSpeed; + entity.motionY = 0; + entity.motionZ = dashDirection.zCoord * dashSpeed; + entity.velocityChanged = true; // Trail particles - world.spawnParticle("smoke", npc.posX, npc.posY + 0.5, npc.posZ, 0, 0, 0); + world.spawnParticle("smoke", entity.posX, entity.posY + 0.5, entity.posZ, 0, 0, 0); } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { - npc.motionX = 0; - npc.motionZ = 0; - npc.velocityChanged = true; + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { + EntityLivingBase entity = (EntityLivingBase) holder; + entity.motionX = 0; + entity.motionZ = 0; + entity.velocityChanged = true; dashDirection = null; chosenDirection = null; } @Override - public void onInterrupt(EntityNPCInterface npc, net.minecraft.util.DamageSource source, float damage) { - npc.motionX = 0; - npc.motionZ = 0; - npc.velocityChanged = true; + public void onInterrupt(IAbilityHolder holder, DamageSource source, float damage) { + EntityLivingBase entity = (EntityLivingBase) holder; + entity.motionX = 0; + entity.motionZ = 0; + entity.velocityChanged = true; dashDirection = null; chosenDirection = null; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java index 8afc45063..aae12c7b6 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityGuard; @@ -69,21 +70,21 @@ public TargetingMode[] getAllowedTargetingModes() { } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { lastAttacker = null; counterTriggered = false; } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { // Counter attack logic if triggered if (canCounter && counterTriggered && lastAttacker != null && !world.isRemote) { // Apply counter damage with scripted event support - boolean wasHit = applyAbilityDamage(npc, lastAttacker, counterDamage, 0.5f, 0); + boolean wasHit = applyAbilityDamage(holder, lastAttacker, counterDamage, 0.5f, 0); // Play counter sound if hit wasn't cancelled if (wasHit) { - world.playSoundAtEntity(npc, "random.wood_click", 1.0f, 1.2f); + world.playSoundAtEntity((EntityLivingBase) holder, "random.wood_click", 1.0f, 1.2f); } counterTriggered = false; diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java index 9ac5509d5..a1e4b8634 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityHazard; @@ -111,19 +112,21 @@ public TargetingMode[] getAllowedTargetingModes() { public float getTelegraphRadius() { return radius; } @Override - public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBase target) { - TelegraphInstance instance = super.createTelegraph(npc, target); + public TelegraphInstance createTelegraph(IAbilityHolder holder, EntityLivingBase target) { + TelegraphInstance instance = super.createTelegraph(holder, target); if (instance == null) return null; + EntityLivingBase entity = (EntityLivingBase) holder; + // Control telegraph following based on placement mode switch (placement) { case AT_CASTER: case FOLLOW_CASTER: // Telegraph stays at caster position, no following instance.setEntityIdToFollow(-1); - instance.setX(npc.posX); - instance.setY(npc.posY); - instance.setZ(npc.posZ); + instance.setX(entity.posX); + instance.setY(entity.posY); + instance.setZ(entity.posZ); break; case AT_TARGET: // Telegraph follows target during windup, locks on execute @@ -170,14 +173,16 @@ private double[] calculateOffsetPosition(double baseX, double baseY, double base } @Override - public void onWindUpTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onWindUpTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { // AT_CASTER locks immediately, AT_TARGET follows during windup and locks on execute if (tick == 0) { + EntityLivingBase entity = (EntityLivingBase) holder; + switch (placement) { case AT_CASTER: - zoneX = npc.posX; - zoneY = npc.posY; - zoneZ = npc.posZ; + zoneX = entity.posX; + zoneY = entity.posY; + zoneZ = entity.posZ; positionLocked = true; break; case AT_TARGET: @@ -193,17 +198,19 @@ public void onWindUpTick(EntityNPCInterface npc, EntityLivingBase target, World } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { // Lock position from telegraph (which was following target) or calculate it now TelegraphInstance telegraph = getTelegraphInstance(); + EntityLivingBase entity = (EntityLivingBase) holder; + switch (placement) { case AT_CASTER: // Already locked during windup if (!positionLocked) { - zoneX = npc.posX; - zoneY = npc.posY; - zoneZ = npc.posZ; + zoneX = entity.posX; + zoneY = entity.posY; + zoneZ = entity.posZ; } break; case AT_TARGET: @@ -219,15 +226,15 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor zoneY = pos[1]; zoneZ = pos[2]; } else { - zoneX = npc.posX; - zoneY = npc.posY; - zoneZ = npc.posZ; + zoneX = entity.posX; + zoneY = entity.posY; + zoneZ = entity.posZ; } break; case FOLLOW_CASTER: - zoneX = npc.posX; - zoneY = npc.posY; - zoneZ = npc.posZ; + zoneX = entity.posX; + zoneY = entity.posY; + zoneZ = entity.posZ; break; case FOLLOW_TARGET: if (target != null) { @@ -235,9 +242,9 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor zoneY = target.posY; zoneZ = target.posZ; } else { - zoneX = npc.posX; - zoneY = npc.posY; - zoneZ = npc.posZ; + zoneX = entity.posX; + zoneY = entity.posY; + zoneZ = entity.posZ; } break; } @@ -246,17 +253,19 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (world.isRemote) return; damagedThisTick.clear(); ticksSinceDamage++; + EntityLivingBase entity = (EntityLivingBase) holder; + switch (placement) { case FOLLOW_CASTER: - zoneX = npc.posX; - zoneY = npc.posY; - zoneZ = npc.posZ; + zoneX = entity.posX; + zoneY = entity.posY; + zoneZ = entity.posZ; break; case FOLLOW_TARGET: if (target != null) { @@ -280,27 +289,27 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, searchBox); - for (EntityLivingBase entity : entities) { - if (entity == npc && !affectsCaster) continue; - if (damagedThisTick.contains(entity.getEntityId())) continue; - if (!isInZone(entity, npc)) continue; + for (EntityLivingBase currentEntity : entities) { + if (currentEntity == entity && !affectsCaster) continue; + if (damagedThisTick.contains(currentEntity.getEntityId())) continue; + if (!isInZone(currentEntity, entity)) continue; if (damagePerTick > 0) { if (ignoreInvulnFrames) { - entity.hurtResistantTime = 0; + currentEntity.hurtResistantTime = 0; } // Apply damage with scripted event support (no knockback for hazard ticks) - boolean wasHit = applyAbilityDamage(npc, entity, damagePerTick, 0, 0); + boolean wasHit = applyAbilityDamage(holder, currentEntity, damagePerTick, 0, 0); if (!wasHit) continue; // Skip debuffs if hit was cancelled } - applyDebuffs(entity); - damagedThisTick.add(entity.getEntityId()); + applyDebuffs(currentEntity); + damagedThisTick.add(currentEntity.getEntityId()); } } } - private boolean isInZone(EntityLivingBase entity, EntityNPCInterface npc) { + private boolean isInZone(EntityLivingBase entity, EntityLivingBase caster) { double dx = entity.posX - zoneX; double dz = entity.posZ - zoneZ; double dist = Math.sqrt(dx * dx + dz * dz); @@ -312,7 +321,7 @@ private boolean isInZone(EntityLivingBase entity, EntityNPCInterface npc) { return dist >= innerRadius && dist <= radius; case CONE: if (dist > radius) return false; - float casterYaw = npc.rotationYaw; + float casterYaw = caster.rotationYaw; double angleToEntity = Math.toDegrees(Math.atan2(-dx, dz)); double angleDiff = Math.abs(normalizeAngle(angleToEntity - casterYaw)); return angleDiff <= coneAngle / 2; @@ -346,13 +355,13 @@ private void applyDebuffs(EntityLivingBase target) { } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { damagedThisTick.clear(); positionLocked = false; } @Override - public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) { + public void onInterrupt(IAbilityHolder holder, DamageSource source, float damage) { damagedThisTick.clear(); positionLocked = false; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java index 4a393682b..e85a5f724 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java @@ -10,6 +10,7 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.World; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityHeal; @@ -67,27 +68,31 @@ public TargetingMode[] getAllowedTargetingModes() { } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { if (world.isRemote) return; + EntityLivingBase entity = (EntityLivingBase) holder; + healedAllies.clear(); if (instantHeal) { if (healSelf) { - healEntity(npc); - spawnHealParticles(world, npc); + healEntity(entity); + spawnHealParticles(world, entity); } if (healAllies && healRadius > 0) { - healAlliesInRadius(npc, world); + healAlliesInRadius(holder, world); } } } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (world.isRemote || instantHeal) return; + EntityLivingBase entity = (EntityLivingBase) holder; + // Heal over time - distribute heal across active ticks if (tick % 10 == 0) { // Calculate tick-based heal for fixed amount @@ -97,9 +102,9 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World float selfTickHeal = tickHeal; // Add percentage-based heal portion if (healPercent > 0) { - selfTickHeal += (npc.getMaxHealth() * healPercent / (float) activeTicks) * 10; + selfTickHeal += (entity.getMaxHealth() * healPercent / (float) activeTicks) * 10; } - npc.heal(selfTickHeal); + entity.heal(selfTickHeal); } if (healAllies && healRadius > 0) { @@ -125,24 +130,26 @@ private void healEntity(EntityLivingBase entity) { entity.heal(totalHeal); } - private void healAlliesInRadius(EntityNPCInterface npc, World world) { + private void healAlliesInRadius(IAbilityHolder holder, World world) { + EntityLivingBase entity = (EntityLivingBase) holder; + AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox( - npc.posX - healRadius, npc.posY - 2, npc.posZ - healRadius, - npc.posX + healRadius, npc.posY + 3, npc.posZ + healRadius + entity.posX - healRadius, entity.posY - 2, entity.posZ - healRadius, + entity.posX + healRadius, entity.posY + 3, entity.posZ + healRadius ); @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, aabb); - for (Entity entity : entities) { - if (!(entity instanceof EntityLivingBase)) continue; - if (entity == npc) continue; + for (Entity currentEntity : entities) { + if (!(currentEntity instanceof EntityLivingBase)) continue; + if (currentEntity == entity) continue; - EntityLivingBase living = (EntityLivingBase) entity; + EntityLivingBase living = (EntityLivingBase) currentEntity; // Only heal other NPCs (allies) if (living instanceof EntityNPCInterface) { - float dist = npc.getDistanceToEntity(living); + float dist = entity.getDistanceToEntity(living); if (dist <= healRadius) { healEntity(living); healedAllies.add(living); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java index b76412606..448724f27 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityHeavyHit; @@ -61,11 +62,11 @@ public TargetingMode[] getAllowedTargetingModes() { } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { if (world.isRemote || target == null) return; // Apply damage with scripted event support - boolean wasHit = applyAbilityDamage(npc, target, damage, knockback, knockbackUp); + boolean wasHit = applyAbilityDamage(holder, target, damage, knockback, knockbackUp); // Apply stun (slowness + weakness) if the hit wasn't cancelled if (wasHit && stunTicks > 0) { @@ -75,7 +76,7 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { // Heavy Hit is instant, no active tick needed } 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 afc8f6eb8..42e0a78b7 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 @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityOrb; @@ -85,10 +86,11 @@ public TargetingMode[] getAllowedTargetingModes() { } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { - startX = orbX = npc.posX; - startY = orbY = npc.posY + npc.getEyeHeight() * 0.8; - startZ = orbZ = npc.posZ; + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { + EntityLivingBase entity = (EntityLivingBase) holder; + startX = orbX = entity.posX; + startY = orbY = entity.posY + entity.getEyeHeight() * 0.8; + startZ = orbZ = entity.posZ; hasHit = false; ticksAlive = 0; @@ -103,8 +105,8 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor velocityZ = (dz / len) * orbSpeed; } } else { - float yaw = (float) Math.toRadians(npc.rotationYaw); - float pitch = (float) Math.toRadians(npc.rotationPitch); + float yaw = (float) Math.toRadians(entity.rotationYaw); + float pitch = (float) Math.toRadians(entity.rotationPitch); velocityX = -Math.sin(yaw) * Math.cos(pitch) * orbSpeed; velocityY = -Math.sin(pitch) * orbSpeed; velocityZ = Math.cos(yaw) * Math.cos(pitch) * orbSpeed; @@ -112,7 +114,7 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (hasHit) return; ticksAlive++; @@ -172,11 +174,13 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World orbZ += velocityZ; if (!world.isRemote) { - checkCollision(npc, world); + checkCollision(holder, world); } } - private void checkCollision(EntityNPCInterface npc, World world) { + private void checkCollision(IAbilityHolder holder, World world) { + EntityLivingBase caster = (EntityLivingBase) holder; + AxisAlignedBB hitBox = AxisAlignedBB.getBoundingBox( orbX - orbSize, orbY - orbSize, orbZ - orbSize, orbX + orbSize, orbY + orbSize, orbZ + orbSize @@ -186,15 +190,15 @@ private void checkCollision(EntityNPCInterface npc, World world) { List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, hitBox); for (EntityLivingBase entity : entities) { - if (entity == npc) continue; + if (entity == caster) continue; hasHit = true; if (explosive) { - doExplosion(npc, world); + doExplosion(holder, world); } else { // Apply damage with scripted event support - boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback, 0.2f); + boolean wasHit = applyAbilityDamage(holder, entity, damage, knockback, 0.2f); if (wasHit) { applyEffects(entity); } @@ -205,12 +209,12 @@ private void checkCollision(EntityNPCInterface npc, World world) { if (!hasHit && world.getBlock((int)orbX, (int)orbY, (int)orbZ).getMaterial().isSolid()) { hasHit = true; if (explosive) { - doExplosion(npc, world); + doExplosion(holder, world); } } } - private void doExplosion(EntityNPCInterface npc, World world) { + private void doExplosion(IAbilityHolder holder, World world) { AxisAlignedBB explosionBox = AxisAlignedBB.getBoundingBox( orbX - explosionRadius, orbY - explosionRadius, orbZ - explosionRadius, orbX + explosionRadius, orbY + explosionRadius, orbZ + explosionRadius @@ -219,8 +223,10 @@ private void doExplosion(EntityNPCInterface npc, World world) { @SuppressWarnings("unchecked") List blastTargets = world.getEntitiesWithinAABB(EntityLivingBase.class, explosionBox); + EntityLivingBase caster = (EntityLivingBase) holder; + for (EntityLivingBase blastTarget : blastTargets) { - if (blastTarget == npc) continue; + if (blastTarget == caster) continue; double dist = Math.sqrt( Math.pow(blastTarget.posX - orbX, 2) + @@ -231,7 +237,7 @@ private void doExplosion(EntityNPCInterface npc, World world) { if (dist <= explosionRadius) { float falloff = 1.0f - (float)(dist / explosionRadius) * explosionDamageFalloff; // Apply damage with scripted event support - boolean wasHit = applyAbilityDamage(npc, blastTarget, damage * falloff, knockback * falloff, 0.3f); + boolean wasHit = applyAbilityDamage(holder, blastTarget, damage * falloff, knockback * falloff, 0.3f); if (wasHit) { applyEffects(blastTarget); } @@ -264,13 +270,13 @@ private void applyEffects(EntityLivingBase target) { } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { hasHit = false; ticksAlive = 0; } @Override - public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) { + public void onInterrupt(IAbilityHolder holder, DamageSource source, float damage) { hasHit = false; ticksAlive = 0; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java index b5f47e8b1..c5a5d38af 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java @@ -10,6 +10,7 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.world.World; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityProjectile; @@ -66,13 +67,15 @@ public TargetingMode[] getAllowedTargetingModes() { } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { if (world.isRemote || target == null) return; + EntityLivingBase entity = (EntityLivingBase) holder; + // Calculate direction to target - double dx = target.posX - npc.posX; - double dy = (target.posY + target.height / 2) - (npc.posY + npc.getEyeHeight()); - double dz = target.posZ - npc.posZ; + double dx = target.posX - entity.posX; + double dy = (target.posY + target.height / 2) - (entity.posY + entity.getEyeHeight()); + double dz = target.posZ - entity.posZ; double len = Math.sqrt(dx * dx + dy * dy + dz * dz); if (len > 0) { @@ -83,10 +86,10 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor // Deal instant damage with scripted event support // TODO: Use custom EntityAbilityProjectile for actual tracking - applyAbilityDamageWithDirection(npc, target, damage, knockback, 0.1f, dx, dz); + applyAbilityDamageWithDirection(holder, target, damage, knockback, 0.1f, dx, dz); // Play sound - world.playSoundAtEntity(npc, "random.bow", 1.0f, 0.8f); + world.playSoundAtEntity(entity, "random.bow", 1.0f, 0.8f); // Handle splash damage for explosive projectiles if (explosive && explosionRadius > 0) { @@ -94,14 +97,14 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor List entities = world.getEntitiesWithinAABBExcludingEntity(target, target.boundingBox.expand(explosionRadius, explosionRadius, explosionRadius)); - for (Entity entity : entities) { - if (entity instanceof EntityLivingBase && entity != npc) { - EntityLivingBase living = (EntityLivingBase) entity; + for (Entity currentEntity : entities) { + if (currentEntity instanceof EntityLivingBase && currentEntity != entity) { + EntityLivingBase living = (EntityLivingBase) currentEntity; float dist = target.getDistanceToEntity(living); if (dist < explosionRadius) { float falloff = 1.0f - (dist / explosionRadius); // Apply splash damage with scripted event support (no knockback) - applyAbilityDamage(npc, living, damage * falloff * 0.5f, 0, 0); + applyAbilityDamage(holder, living, damage * falloff * 0.5f, 0, 0); } } } @@ -118,13 +121,13 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor } // Spawn projectile particles (visual trail) - spawnProjectileParticles(world, npc, target); + spawnProjectileParticles(world, entity, target); } - private void spawnProjectileParticles(World world, EntityNPCInterface npc, EntityLivingBase target) { - double startX = npc.posX; - double startY = npc.posY + npc.getEyeHeight(); - double startZ = npc.posZ; + private void spawnProjectileParticles(World world, EntityLivingBase caster, EntityLivingBase target) { + double startX = caster.posX; + double startY = caster.posY + caster.getEyeHeight(); + double startZ = caster.posZ; double endX = target.posX; double endY = target.posY + target.height / 2; double endZ = target.posZ; @@ -153,7 +156,7 @@ private void spawnProjectileParticles(World world, EntityNPCInterface npc, Entit } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { // Projectile is instant, nothing to do per-tick } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java index 1204dbc4d..cb99ead4a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java @@ -12,6 +12,7 @@ import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.DamageSource; import net.minecraft.world.World; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityShockwave; @@ -70,37 +71,38 @@ public TargetingMode[] getAllowedTargetingModes() { public float getTelegraphRadius() { return pushRadius; } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { executed = false; } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (executed) return; executed = true; + EntityLivingBase entity = (EntityLivingBase) holder; // Play shockwave sound - world.playSoundAtEntity(npc, "random.explode", 0.5f, 1.5f); + world.playSoundAtEntity(entity, "random.explode", 0.5f, 1.5f); // Get all entities in radius - AxisAlignedBB box = npc.boundingBox.expand(pushRadius, pushRadius / 2, pushRadius); + AxisAlignedBB box = entity.boundingBox.expand(pushRadius, pushRadius / 2, pushRadius); @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, box); int count = 0; - for (EntityLivingBase entity : entities) { - if (entity == npc) continue; - if (entity.isDead) continue; + for (EntityLivingBase currentEntity : entities) { + if (currentEntity == entity) continue; + if (currentEntity.isDead) continue; - double dist = npc.getDistanceToEntity(entity); + double dist = entity.getDistanceToEntity(currentEntity); if (dist > pushRadius) continue; count++; if (count > maxTargets) break; // Calculate push direction (away from caster) - double dx = entity.posX - npc.posX; - double dz = entity.posZ - npc.posZ; + double dx = currentEntity.posX - entity.posX; + double dz = currentEntity.posZ - entity.posZ; double len = Math.sqrt(dx * dx + dz * dz); if (len > 0) { @@ -119,23 +121,23 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World float finalPushUp = pushUp * distFactor; // Apply damage with custom knockback direction - boolean wasHit = applyAbilityDamageWithDirection(npc, entity, damage * distFactor, finalPush, finalPushUp, dx, dz); + boolean wasHit = applyAbilityDamageWithDirection(holder, currentEntity, damage * distFactor, finalPush, finalPushUp, dx, dz); // Apply stun if hit connected if (wasHit && stunDuration > 0) { - entity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunDuration, 10)); - entity.addPotionEffect(new PotionEffect(Potion.weakness.id, stunDuration, 2)); + currentEntity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunDuration, 10)); + currentEntity.addPotionEffect(new PotionEffect(Potion.weakness.id, stunDuration, 2)); } } } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { executed = false; } @Override - public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) { + public void onInterrupt(IAbilityHolder holder, DamageSource source, float damage) { executed = false; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java index 1d72f23cc..63cd324a7 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java @@ -13,6 +13,7 @@ import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.world.World; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilitySlam; @@ -88,13 +89,14 @@ public boolean hasAbilityMovement() { } @Override - public void onWindUpTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onWindUpTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { // Update target position during windup if (targetingMode == TargetingMode.AOE_SELF) { + EntityLivingBase entity = (EntityLivingBase) holder; // AOE_SELF: slam at NPC's current position - targetX = npc.posX; - targetY = npc.posY; - targetZ = npc.posZ; + targetX = entity.posX; + targetY = entity.posY; + targetZ = entity.posZ; } else if (targetingMode == TargetingMode.AOE_TARGET && target != null && !target.isDead) { // AOE_TARGET: telegraph follows target via setEntityIdToFollow targetX = target.posX; @@ -104,13 +106,14 @@ public void onWindUpTick(EntityNPCInterface npc, EntityLivingBase target, World } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { // Lock in the destination at moment of launch + EntityLivingBase entity = (EntityLivingBase) holder; if (targetingMode == TargetingMode.AOE_SELF) { // AOE_SELF: slam in place (just jump up) - targetX = npc.posX; - targetY = npc.posY; - targetZ = npc.posZ; + targetX = entity.posX; + targetY = entity.posY; + targetZ = entity.posZ; } else if (targetingMode == TargetingMode.AOE_TARGET && target != null && !target.isDead) { // AOE_TARGET: leap to target's current position targetX = target.posX; @@ -118,9 +121,9 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor targetZ = target.posZ; } else { // Fallback: slam in place - targetX = npc.posX; - targetY = npc.posY; - targetZ = npc.posZ; + targetX = entity.posX; + targetY = entity.posY; + targetZ = entity.posZ; } hasLaunched = false; @@ -128,31 +131,33 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor airTicks = 0; // Reset fall distance to prevent fall damage during slam - npc.fallDistance = 0; + entity.fallDistance = 0; // Calculate and apply leap velocity - launchTowardTarget(npc); + launchTowardTarget(holder); } /** * Calculate ballistic arc and launch NPC toward target. * Accounts for Minecraft's drag physics to actually reach the destination. */ - private void launchTowardTarget(EntityNPCInterface npc) { - double dx = targetX - npc.posX; - double dy = targetY - npc.posY; - double dz = targetZ - npc.posZ; + private void launchTowardTarget(IAbilityHolder holder) { + EntityLivingBase entity = (EntityLivingBase) holder; + + double dx = targetX - entity.posX; + double dy = targetY - entity.posY; + double dz = targetZ - entity.posZ; double horizontalDist = Math.sqrt(dx * dx + dz * dz); // For AOE_SELF or very close targets, just hop in place if (horizontalDist < 0.5) { - npc.motionX = 0; - npc.motionZ = 0; - npc.motionY = 0.8 * leapSpeed; + entity.motionX = 0; + entity.motionZ = 0; + entity.motionY = 0.8 * leapSpeed; hasLaunched = true; - npc.setNpcJumpingState(true); - npc.velocityChanged = true; - npc.worldObj.playSoundAtEntity(npc, "mob.irongolem.throw", 0.8f, 0.8f); + setJumpState(holder, true); + entity.velocityChanged = true; + entity.worldObj.playSoundAtEntity(entity, "mob.irongolem.throw", 0.8f, 0.8f); return; } @@ -162,8 +167,8 @@ private void launchTowardTarget(EntityNPCInterface npc) { dx *= scale; dz *= scale; horizontalDist = maxLeapDistance; - targetX = npc.posX + dx; - targetZ = npc.posZ + dz; + targetX = entity.posX + dx; + targetZ = entity.posZ + dz; } // Choose flight time based on distance - shorter distances = faster @@ -209,95 +214,99 @@ private void launchTowardTarget(EntityNPCInterface npc) { double dirX = dx / horizontalDist; double dirZ = dz / horizontalDist; - npc.motionX = dirX * vHorizontal; - npc.motionZ = dirZ * vHorizontal; - npc.motionY = vy; + entity.motionX = dirX * vHorizontal; + entity.motionZ = dirZ * vHorizontal; + entity.motionY = vy; hasLaunched = true; - npc.setNpcJumpingState(true); - npc.velocityChanged = true; + setJumpState(holder, true); + entity.velocityChanged = true; // Face the target float targetYaw = (float) (Math.atan2(-dx, dz) * 180.0D / Math.PI); - npc.rotationYaw = targetYaw; - npc.rotationYawHead = targetYaw; + entity.rotationYaw = targetYaw; + entity.rotationYawHead = targetYaw; // Play launch sound - npc.worldObj.playSoundAtEntity(npc, "mob.irongolem.throw", 0.8f, 0.8f); + entity.worldObj.playSoundAtEntity(entity, "mob.irongolem.throw", 0.8f, 0.8f); } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (!hasLaunched) return; if (hasLanded) return; airTicks++; + EntityLivingBase entity = (EntityLivingBase) holder; + // Continuously reset fall distance during slam to prevent fall damage - npc.fallDistance = 0; + entity.fallDistance = 0; // Check for landing - if (npc.onGround && airTicks > 3) { + if (entity.onGround && airTicks > 3) { // Landed! - onLanding(npc, world); + onLanding(holder, world); return; } // Timeout protection - force landing after max air time if (airTicks >= maxAirTicks) { - onLanding(npc, world); + onLanding(holder, world); return; } // While in air, face toward target - double dx = targetX - npc.posX; - double dz = targetZ - npc.posZ; + double dx = targetX - entity.posX; + double dz = targetZ - entity.posZ; float targetYaw = (float) (Math.atan2(-dx, dz) * 180.0D / Math.PI); - npc.rotationYaw = targetYaw; - npc.rotationYawHead = targetYaw; + entity.rotationYaw = targetYaw; + entity.rotationYawHead = targetYaw; } /** * Called when NPC lands - deal AOE damage. */ - private void onLanding(EntityNPCInterface npc, World world) { + private void onLanding(IAbilityHolder holder, World world) { + EntityLivingBase entity = (EntityLivingBase) holder; + hasLanded = true; - npc.setNpcJumpingState(false); + setJumpState(holder, false); // Reset fall distance to prevent fall damage on landing - npc.fallDistance = 0; + entity.fallDistance = 0; // Stop horizontal momentum - npc.motionX = 0; - npc.motionZ = 0; - npc.velocityChanged = true; + entity.motionX = 0; + entity.motionZ = 0; + entity.velocityChanged = true; if (world.isRemote) return; // Find all entities in radius @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABBExcludingEntity( - npc, npc.boundingBox.expand(radius, radius / 2, radius)); + entity, entity.boundingBox.expand(radius, radius / 2, radius)); - for (Entity entity : entities) { - if (entity instanceof EntityLivingBase && entity != npc) { - EntityLivingBase livingTarget = (EntityLivingBase) entity; + for (Entity currentEntity : entities) { + if (currentEntity instanceof EntityLivingBase && currentEntity != entity) { + EntityLivingBase livingTarget = (EntityLivingBase) currentEntity; // Check if actually within radius (bounding box is a cube, we want a circle) - double dx = livingTarget.posX - npc.posX; - double dz = livingTarget.posZ - npc.posZ; + double dx = livingTarget.posX - entity.posX; + double dz = livingTarget.posZ - entity.posZ; if (dx * dx + dz * dz <= radius * radius) { // Apply damage with scripted event support (0.3f is the upward knockback boost) - applyAbilityDamage(npc, livingTarget, damage, knockbackStrength, 0.3f); + applyAbilityDamage(holder, livingTarget, damage, knockbackStrength, 0.3f); } } } // Play impact sound - world.playSoundAtEntity(npc, "random.explode", 0.5f, 1.2f); + world.playSoundAtEntity(entity, "random.explode", 0.5f, 1.2f); // Spawn particles - spawnSlamParticles(world, npc.posX, npc.posY, npc.posZ); + spawnSlamParticles(world, entity.posX, entity.posY, entity.posZ); } /** @@ -337,16 +346,16 @@ private void spawnSlamParticles(World world, double x, double y, double z) { } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { - npc.setNpcJumpingState(false); + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { + setJumpState(holder, false); hasLaunched = false; hasLanded = false; airTicks = 0; } @Override - public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) { - npc.setNpcJumpingState(false); + public void onInterrupt(IAbilityHolder holder, DamageSource source, float damage) { + setJumpState(holder, false); hasLaunched = false; hasLanded = false; airTicks = 0; @@ -361,18 +370,20 @@ public void reset() { } @Override - public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBase target) { + public TelegraphInstance createTelegraph(IAbilityHolder holder, EntityLivingBase target) { // Check if telegraph should be shown if (!isShowTelegraph() || getTelegraphType() == TelegraphType.NONE) { return null; } + EntityLivingBase entity = (EntityLivingBase) holder; + // Telegraph shows at landing zone if (targetingMode == TargetingMode.AOE_SELF) { // AOE_SELF: telegraph at NPC position, does NOT follow - targetX = npc.posX; - targetY = npc.posY; - targetZ = npc.posZ; + targetX = entity.posX; + targetY = entity.posY; + targetZ = entity.posZ; } else if (targetingMode == TargetingMode.AOE_TARGET && target != null) { // AOE_TARGET: telegraph at target position, follows target during windup targetX = target.posX; @@ -380,13 +391,13 @@ public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBas targetZ = target.posZ; } else { // Fallback to NPC position - targetX = npc.posX; - targetY = npc.posY; - targetZ = npc.posZ; + targetX = entity.posX; + targetY = entity.posY; + targetZ = entity.posZ; } // Create telegraph at the appropriate position - double groundY = findGroundLevel(npc.worldObj, targetX, targetY, targetZ); + double groundY = findGroundLevel(entity.worldObj, targetX, targetY, targetZ); Telegraph telegraph = Telegraph.circle(radius); telegraph.setDurationTicks(windUpTicks); @@ -395,8 +406,8 @@ public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBas telegraph.setWarningStartTick(Math.max(5, windUpTicks / 4)); telegraph.setHeightOffset(telegraphHeightOffset); - TelegraphInstance instance = new TelegraphInstance(telegraph, targetX, groundY, targetZ, npc.rotationYaw); - instance.setCasterEntityId(npc.getEntityId()); + TelegraphInstance instance = new TelegraphInstance(telegraph, targetX, groundY, targetZ, entity.rotationYaw); + instance.setCasterEntityId(entity.getEntityId()); // AOE_TARGET: telegraph follows target during windup if (targetingMode == TargetingMode.AOE_TARGET && target != null) { @@ -407,6 +418,16 @@ public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBas return instance; } + private boolean isNPC(IAbilityHolder holder) { + return holder instanceof EntityNPCInterface; + } + + private void setJumpState(IAbilityHolder holder, boolean b) { + if (isNPC(holder)) { + ((EntityNPCInterface) holder).setNpcJumpingState(b); + } + } + @Override public float getTelegraphRadius() { return radius; diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java index f4a4780e8..0f6cc1366 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityTeleport; @@ -93,38 +94,40 @@ public TargetingMode[] getAllowedTargetingModes() { } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { currentBlink = 0; ticksSinceLastBlink = blinkDelayTicks; // Trigger first blink immediately } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (currentBlink >= blinkCount) return; ticksSinceLastBlink++; if (ticksSinceLastBlink >= blinkDelayTicks) { - performBlink(npc, target, world); + performBlink(holder, target, world); currentBlink++; ticksSinceLastBlink = 0; } } - private void performBlink(EntityNPCInterface npc, EntityLivingBase target, World world) { + private void performBlink(IAbilityHolder holder, EntityLivingBase target, World world) { if (world.isRemote) return; - double oldX = npc.posX; - double oldY = npc.posY; - double oldZ = npc.posZ; + EntityLivingBase entity = (EntityLivingBase) holder; - Vec3 destination = calculateDestination(npc, target, world); + double oldX = entity.posX; + double oldY = entity.posY; + double oldZ = entity.posZ; + + Vec3 destination = calculateDestination(entity, target, world); if (destination == null) return; // Verify line of sight if required - if (requireLineOfSight && !hasLineOfSight(world, oldX, oldY + npc.getEyeHeight(), oldZ, - destination.xCoord, destination.yCoord + npc.getEyeHeight(), destination.zCoord)) { - destination = findValidPositionAlongLine(world, npc, oldX, oldY, oldZ, + if (requireLineOfSight && !hasLineOfSight(world, oldX, oldY + entity.getEyeHeight(), oldZ, + destination.xCoord, destination.yCoord + entity.getEyeHeight(), destination.zCoord)) { + destination = findValidPositionAlongLine(world, entity, oldX, oldY, oldZ, destination.xCoord, destination.yCoord, destination.zCoord); if (destination == null) return; } @@ -145,25 +148,25 @@ private void performBlink(EntityNPCInterface npc, EntityLivingBase target, World // Damage at origin if (damageAtStart) { - dealDamageAt(npc, world, oldX, oldY, oldZ); + dealDamageAt(holder, world, oldX, oldY, oldZ); } // Spawn particles at origin spawnTeleportParticles(world, oldX, oldY, oldZ); // Teleport - npc.setPositionAndUpdate(destination.xCoord, destination.yCoord, destination.zCoord); - npc.fallDistance = 0; + entity.setPositionAndUpdate(destination.xCoord, destination.yCoord, destination.zCoord); + entity.fallDistance = 0; // Spawn particles at destination spawnTeleportParticles(world, destination.xCoord, destination.yCoord, destination.zCoord); // Play teleport sound - world.playSoundAtEntity(npc, "mob.endermen.portal", 1.0f, 1.0f); + world.playSoundAtEntity(entity, "mob.endermen.portal", 1.0f, 1.0f); // Damage at destination if (damageAtEnd) { - dealDamageAt(npc, world, destination.xCoord, destination.yCoord, destination.zCoord); + dealDamageAt(holder, world, destination.xCoord, destination.yCoord, destination.zCoord); } // Face target after teleport @@ -171,8 +174,8 @@ private void performBlink(EntityNPCInterface npc, EntityLivingBase target, World double dx = target.posX - destination.xCoord; double dz = target.posZ - destination.zCoord; float newYaw = (float) Math.toDegrees(Math.atan2(-dx, dz)); - npc.rotationYaw = newYaw; - npc.rotationYawHead = newYaw; + entity.rotationYaw = newYaw; + entity.rotationYawHead = newYaw; } } @@ -188,21 +191,21 @@ private void spawnTeleportParticles(World world, double x, double y, double z) { } } - private Vec3 calculateDestination(EntityNPCInterface npc, EntityLivingBase target, World world) { + private Vec3 calculateDestination(EntityLivingBase entity, EntityLivingBase target, World world) { double newX, newY, newZ; switch (pattern) { case TOWARD_TARGET: if (target != null) { - double dx = target.posX - npc.posX; - double dz = target.posZ - npc.posZ; + double dx = target.posX - entity.posX; + double dz = target.posZ - entity.posZ; double dist = Math.sqrt(dx * dx + dz * dz); if (dist > 0) { double blinkDist = Math.min(blinkRadius, dist - 2.0); blinkDist = Math.max(minBlinkRadius, blinkDist); - newX = npc.posX + (dx / dist) * blinkDist; - newZ = npc.posZ + (dz / dist) * blinkDist; - newY = findSafeY(world, newX, npc.posY, newZ); + newX = entity.posX + (dx / dist) * blinkDist; + newZ = entity.posZ + (dz / dist) * blinkDist; + newY = findSafeY(world, newX, entity.posY, newZ); return Vec3.createVectorHelper(newX, newY, newZ); } } @@ -210,8 +213,8 @@ private Vec3 calculateDestination(EntityNPCInterface npc, EntityLivingBase targe case AWAY_FROM_TARGET: if (target != null) { - double dx = npc.posX - target.posX; - double dz = npc.posZ - target.posZ; + double dx = entity.posX - target.posX; + double dz = entity.posZ - target.posZ; double dist = Math.sqrt(dx * dx + dz * dz); if (dist > 0) { dx /= dist; @@ -224,9 +227,9 @@ private Vec3 calculateDestination(EntityNPCInterface npc, EntityLivingBase targe dz /= len; } double blinkDist = minBlinkRadius + RANDOM.nextDouble() * (blinkRadius - minBlinkRadius); - newX = npc.posX + dx * blinkDist; - newZ = npc.posZ + dz * blinkDist; - newY = findSafeY(world, newX, npc.posY, newZ); + newX = entity.posX + dx * blinkDist; + newZ = entity.posZ + dz * blinkDist; + newY = findSafeY(world, newX, entity.posY, newZ); return Vec3.createVectorHelper(newX, newY, newZ); } return null; @@ -272,9 +275,9 @@ private Vec3 calculateDestination(EntityNPCInterface npc, EntityLivingBase targe default: double angle = RANDOM.nextDouble() * Math.PI * 2; double blinkDist = minBlinkRadius + RANDOM.nextDouble() * (blinkRadius - minBlinkRadius); - newX = npc.posX + Math.cos(angle) * blinkDist; - newZ = npc.posZ + Math.sin(angle) * blinkDist; - newY = findSafeY(world, newX, npc.posY, newZ); + newX = entity.posX + Math.cos(angle) * blinkDist; + newZ = entity.posZ + Math.sin(angle) * blinkDist; + newY = findSafeY(world, newX, entity.posY, newZ); return Vec3.createVectorHelper(newX, newY, newZ); } } @@ -311,7 +314,7 @@ private boolean hasLineOfSight(World world, double x1, double y1, double z1, return true; } - private Vec3 findValidPositionAlongLine(World world, EntityNPCInterface npc, + private Vec3 findValidPositionAlongLine(World world, EntityLivingBase entity, double x1, double y1, double z1, double x2, double y2, double z2) { double dx = x2 - x1; @@ -333,8 +336,8 @@ private Vec3 findValidPositionAlongLine(World world, EntityNPCInterface npc, double checkY = y1 + dy * d; double checkZ = z1 + dz * d; - if (hasLineOfSight(world, x1, y1 + npc.getEyeHeight(), z1, - checkX, checkY + npc.getEyeHeight(), checkZ)) { + if (hasLineOfSight(world, x1, y1 + entity.getEyeHeight(), z1, + checkX, checkY + entity.getEyeHeight(), checkZ)) { int blockX = MathHelper.floor_double(checkX); int blockY = MathHelper.floor_double(checkY); int blockZ = MathHelper.floor_double(checkZ); @@ -377,24 +380,26 @@ private boolean isSafeLocation(World world, int x, int y, int z) { !headBlock.getMaterial().isSolid(); } - private void dealDamageAt(EntityNPCInterface npc, World world, double x, double y, double z) { + private void dealDamageAt(IAbilityHolder holder, World world, double x, double y, double z) { AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox( x - damageRadius, y - 1, z - damageRadius, x + damageRadius, y + 2, z + damageRadius ); + EntityLivingBase entity = (EntityLivingBase) holder; + @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, aabb); - for (Entity entity : entities) { - if (!(entity instanceof EntityLivingBase)) continue; - if (entity == npc) continue; + for (Entity currentEntity : entities) { + if (!(currentEntity instanceof EntityLivingBase)) continue; + if (currentEntity == entity) continue; - EntityLivingBase living = (EntityLivingBase) entity; + EntityLivingBase living = (EntityLivingBase) currentEntity; double dist = Math.sqrt(Math.pow(living.posX - x, 2) + Math.pow(living.posZ - z, 2)); if (dist <= damageRadius) { // Apply damage with scripted event support (no knockback for teleport damage) - applyAbilityDamage(npc, living, damage, 0, 0); + applyAbilityDamage(holder, living, damage, 0, 0); } } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java index 64e6e07bb..926de0891 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java @@ -13,6 +13,7 @@ import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.DamageSource; import net.minecraft.world.World; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityTrap; @@ -101,10 +102,12 @@ public TargetingMode[] getAllowedTargetingModes() { public float getTelegraphRadius() { return triggerRadius; } @Override - public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBase target) { - TelegraphInstance instance = super.createTelegraph(npc, target); + public TelegraphInstance createTelegraph(IAbilityHolder holder, EntityLivingBase target) { + TelegraphInstance instance = super.createTelegraph(holder, target); if (instance == null) return null; + EntityLivingBase entity = (EntityLivingBase) holder; + // Control telegraph following based on placement mode switch (placement) { case AT_CASTER: @@ -112,14 +115,14 @@ public TelegraphInstance createTelegraph(EntityNPCInterface npc, EntityLivingBas // Telegraph at caster or ahead, no following instance.setEntityIdToFollow(-1); if (placement == TrapPlacement.AHEAD_OF_CASTER) { - double yaw = Math.toRadians(npc.rotationYaw); - instance.setX(npc.posX - Math.sin(yaw) * placementDistance); - instance.setY(npc.posY); - instance.setZ(npc.posZ + Math.cos(yaw) * placementDistance); + double yaw = Math.toRadians(entity.rotationYaw); + instance.setX(entity.posX - Math.sin(yaw) * placementDistance); + instance.setY(entity.posY); + instance.setZ(entity.posZ + Math.cos(yaw) * placementDistance); } else { - instance.setX(npc.posX); - instance.setY(npc.posY); - instance.setZ(npc.posZ); + instance.setX(entity.posX); + instance.setY(entity.posY); + instance.setZ(entity.posZ); } break; case AT_TARGET: @@ -158,20 +161,22 @@ private double[] calculateOffsetPosition(double baseX, double baseY, double base } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { armed = false; triggerCount = 0; ticksSinceLastTrigger = armTime; triggeredEntities.clear(); + EntityLivingBase entity = (EntityLivingBase) holder; + // Use telegraph position if available (for AT_TARGET, it was following target) TelegraphInstance telegraph = getTelegraphInstance(); switch (placement) { case AT_CASTER: - trapX = npc.posX; - trapY = npc.posY; - trapZ = npc.posZ; + trapX = entity.posX; + trapY = entity.posY; + trapZ = entity.posZ; break; case AT_TARGET: // Use telegraph position with offset @@ -186,22 +191,22 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor trapY = pos[1]; trapZ = pos[2]; } else { - trapX = npc.posX; - trapY = npc.posY; - trapZ = npc.posZ; + trapX = entity.posX; + trapY = entity.posY; + trapZ = entity.posZ; } break; case AHEAD_OF_CASTER: - double yaw = Math.toRadians(npc.rotationYaw); - trapX = npc.posX - Math.sin(yaw) * placementDistance; - trapY = npc.posY; - trapZ = npc.posZ + Math.cos(yaw) * placementDistance; + double yaw = Math.toRadians(entity.rotationYaw); + trapX = entity.posX - Math.sin(yaw) * placementDistance; + trapY = entity.posY; + trapZ = entity.posZ + Math.cos(yaw) * placementDistance; break; } } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (!armed) { if (tick >= armTime) { armed = true; @@ -219,6 +224,8 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World return; } + EntityLivingBase entity = (EntityLivingBase) holder; + AxisAlignedBB box = AxisAlignedBB.getBoundingBox( trapX - triggerRadius, trapY - 1, trapZ - triggerRadius, trapX + triggerRadius, trapY + 2, trapZ + triggerRadius @@ -227,29 +234,31 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, box); - for (EntityLivingBase entity : entities) { - if (entity == npc) continue; - if (entity.isDead) continue; - if (maxTriggers == 1 && triggeredEntities.contains(entity.getUniqueID())) continue; + for (EntityLivingBase currentEntity : entities) { + if (currentEntity == entity) continue; + if (currentEntity.isDead) continue; + if (maxTriggers == 1 && triggeredEntities.contains(currentEntity.getUniqueID())) continue; - double dx = entity.posX - trapX; - double dz = entity.posZ - trapZ; + double dx = currentEntity.posX - trapX; + double dz = currentEntity.posZ - trapZ; double dist = Math.sqrt(dx * dx + dz * dz); if (dist <= triggerRadius) { - triggerTrap(npc, entity, world); + triggerTrap(holder, currentEntity, world); return; } } } - private void triggerTrap(EntityNPCInterface npc, EntityLivingBase triggerer, World world) { + private void triggerTrap(IAbilityHolder holder, EntityLivingBase triggerer, World world) { triggerCount++; ticksSinceLastTrigger = 0; triggeredEntities.add(triggerer.getUniqueID()); Set affected = new HashSet<>(); + EntityLivingBase entity = (EntityLivingBase) holder; + if (damageRadius > 0) { AxisAlignedBB box = AxisAlignedBB.getBoundingBox( trapX - damageRadius, trapY - 1, trapZ - damageRadius, @@ -259,54 +268,54 @@ private void triggerTrap(EntityNPCInterface npc, EntityLivingBase triggerer, Wor @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, box); - for (EntityLivingBase entity : entities) { - if (entity == npc) continue; - double dx = entity.posX - trapX; - double dz = entity.posZ - trapZ; + for (EntityLivingBase currentEntity : entities) { + if (currentEntity == entity) continue; + double dx = currentEntity.posX - trapX; + double dz = currentEntity.posZ - trapZ; double dist = Math.sqrt(dx * dx + dz * dz); if (dist <= damageRadius) { - affected.add(entity); + affected.add(currentEntity); } } } else { affected.add(triggerer); } - for (EntityLivingBase entity : affected) { + for (EntityLivingBase currentEntity : affected) { // Apply damage with scripted event support - boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback, knockbackUp); + boolean wasHit = applyAbilityDamage(holder, currentEntity, damage, knockback, knockbackUp); // Only apply effects if the hit wasn't cancelled if (wasHit) { if (stunDuration > 0) { - entity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunDuration, 10)); - entity.addPotionEffect(new PotionEffect(Potion.weakness.id, stunDuration, 2)); + currentEntity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunDuration, 10)); + currentEntity.addPotionEffect(new PotionEffect(Potion.weakness.id, stunDuration, 2)); } if (rootDuration > 0) { - entity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, rootDuration, 127)); + currentEntity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, rootDuration, 127)); } if (slowDuration > 0) { - entity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, slowDuration, slowLevel)); + currentEntity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, slowDuration, slowLevel)); } if (poisonDuration > 0 && poisonLevel >= 0) { - entity.addPotionEffect(new PotionEffect(Potion.poison.id, poisonDuration, poisonLevel)); + currentEntity.addPotionEffect(new PotionEffect(Potion.poison.id, poisonDuration, poisonLevel)); } } } } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { armed = false; triggerCount = 0; triggeredEntities.clear(); } @Override - public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) { + public void onInterrupt(IAbilityHolder holder, DamageSource source, float damage) { armed = false; triggerCount = 0; triggeredEntities.clear(); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java index ab368cdba..55a086f3e 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.client.gui.util.IAbilityConfigCallback; import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig; import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityVortex; @@ -81,23 +82,25 @@ public TargetingMode[] getAllowedTargetingModes() { public float getTelegraphRadius() { return pullRadius; } @Override - public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) { + public void onExecute(IAbilityHolder holder, EntityLivingBase target, World world) { pulledEntities.clear(); pullComplete = false; + EntityLivingBase entity = (EntityLivingBase) holder; + if (aoe) { - AxisAlignedBB box = npc.boundingBox.expand(pullRadius, pullRadius / 2, pullRadius); + AxisAlignedBB box = entity.boundingBox.expand(pullRadius, pullRadius / 2, pullRadius); @SuppressWarnings("unchecked") List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, box); int count = 0; - for (EntityLivingBase entity : entities) { - if (entity == npc) continue; - if (entity.isDead) continue; + for (EntityLivingBase currentEntity : entities) { + if (currentEntity == entity) continue; + if (currentEntity.isDead) continue; - double dist = npc.getDistanceToEntity(entity); + double dist = entity.getDistanceToEntity(currentEntity); if (dist <= pullRadius && dist > minPullDistance) { - pulledEntities.add(entity.getUniqueID()); + pulledEntities.add(currentEntity.getUniqueID()); count++; if (count >= maxTargets) break; } @@ -105,7 +108,7 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor } else { // Single target mode - still check pullRadius if (target != null && !target.isDead) { - double dist = npc.getDistanceToEntity(target); + double dist = entity.getDistanceToEntity(target); if (dist <= pullRadius && dist > minPullDistance) { pulledEntities.add(target.getUniqueID()); } @@ -114,17 +117,19 @@ public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World wor } @Override - public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) { + public void onActiveTick(IAbilityHolder holder, EntityLivingBase target, World world, int tick) { if (pullComplete || pulledEntities.isEmpty()) { return; } - double destX = npc.posX; - double destY = npc.posY; - double destZ = npc.posZ; + EntityLivingBase caster = (EntityLivingBase) holder; + + double destX = caster.posX; + double destY = caster.posY; + double destZ = caster.posZ; if (pullToDistance > 0) { - double yaw = Math.toRadians(npc.rotationYaw); + double yaw = Math.toRadians(caster.rotationYaw); destX -= Math.sin(yaw) * pullToDistance; destZ += Math.cos(yaw) * pullToDistance; } @@ -145,7 +150,7 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World if (dist <= minPullDistance) { pulledEntities.remove(uuid); - onTargetArrived(npc, entity, world); + onTargetArrived(holder, entity, world); continue; } @@ -159,7 +164,7 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World if (damageOnPull && pullDamage > 0) { // Apply damage with scripted event support (no knockback during pull) - applyAbilityDamage(npc, entity, pullDamage, 0, 0); + applyAbilityDamage(holder, entity, pullDamage, 0, 0); } } @@ -168,12 +173,13 @@ public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World } } - private void onTargetArrived(EntityNPCInterface npc, EntityLivingBase entity, World world) { + private void onTargetArrived(IAbilityHolder holder, EntityLivingBase entity, World world) { // Apply damage with scripted event support - boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback * 0.5f, 0); + boolean wasHit = applyAbilityDamage(holder, entity, damage, knockback * 0.5f, 0); // Only apply effects if hit wasn't cancelled if (wasHit) { + if (stunDuration > 0) { entity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunDuration, 10)); entity.addPotionEffect(new PotionEffect(Potion.weakness.id, stunDuration, 2)); @@ -199,13 +205,13 @@ private EntityLivingBase findEntity(World world, UUID uuid) { } @Override - public void onComplete(EntityNPCInterface npc, EntityLivingBase target) { + public void onComplete(IAbilityHolder holder, EntityLivingBase target) { pulledEntities.clear(); pullComplete = false; } @Override - public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) { + public void onInterrupt(IAbilityHolder holder, DamageSource source, float damage) { pulledEntities.clear(); pullComplete = false; } diff --git a/src/main/java/kamkeel/npcs/network/PacketHandler.java b/src/main/java/kamkeel/npcs/network/PacketHandler.java index 2bdf70426..620ed8d41 100644 --- a/src/main/java/kamkeel/npcs/network/PacketHandler.java +++ b/src/main/java/kamkeel/npcs/network/PacketHandler.java @@ -87,6 +87,7 @@ import kamkeel.npcs.network.packets.request.TileEntityGetPacket; import kamkeel.npcs.network.packets.request.TileEntitySavePacket; import kamkeel.npcs.network.packets.request.TraderMarketSavePacket; +import kamkeel.npcs.network.packets.request.ability.*; import kamkeel.npcs.network.packets.request.animation.AnimationGetPacket; import kamkeel.npcs.network.packets.request.animation.AnimationRemovePacket; import kamkeel.npcs.network.packets.request.animation.AnimationSavePacket; @@ -140,9 +141,6 @@ import kamkeel.npcs.network.packets.request.linked.LinkedNPCAddPacket; import kamkeel.npcs.network.packets.request.linked.LinkedNPCRemovePacket; import kamkeel.npcs.network.packets.request.linked.LinkedSetPacket; -import kamkeel.npcs.network.packets.request.ability.AbilitiesGetAllPacket; -import kamkeel.npcs.network.packets.request.ability.AbilitiesNpcGetPacket; -import kamkeel.npcs.network.packets.request.ability.AbilitiesNpcSavePacket; import kamkeel.npcs.network.packets.request.magic.MagicCycleRemovePacket; import kamkeel.npcs.network.packets.request.magic.MagicCycleSavePacket; import kamkeel.npcs.network.packets.request.magic.MagicGetAllPacket; @@ -495,6 +493,8 @@ public void registerRequestPackets() { REQUEST_PACKET.registerPacket(new AbilitiesGetAllPacket()); REQUEST_PACKET.registerPacket(new AbilitiesNpcGetPacket()); REQUEST_PACKET.registerPacket(new AbilitiesNpcSavePacket()); + REQUEST_PACKET.registerPacket(new AbilitiesPlayerGetPacket()); + REQUEST_PACKET.registerPacket(new AbilitiesPlayerSavePacket()); // Other Packets REQUEST_PACKET.registerPacket(new IsGuiOpenInform()); diff --git a/src/main/java/kamkeel/npcs/network/enums/EnumRequestPacket.java b/src/main/java/kamkeel/npcs/network/enums/EnumRequestPacket.java index 1defc81c6..729ff9d22 100644 --- a/src/main/java/kamkeel/npcs/network/enums/EnumRequestPacket.java +++ b/src/main/java/kamkeel/npcs/network/enums/EnumRequestPacket.java @@ -137,6 +137,8 @@ public enum EnumRequestPacket { PlayerDataRemove, PlayerDataMapRegen, PlayerDataSave, + PlayerDataAbilitiesGet, + PlayerDataAbilitiesSave, JobSave, JobGet, diff --git a/src/main/java/kamkeel/npcs/network/packets/request/ability/AbilitiesPlayerGetPacket.java b/src/main/java/kamkeel/npcs/network/packets/request/ability/AbilitiesPlayerGetPacket.java new file mode 100644 index 000000000..c4c884189 --- /dev/null +++ b/src/main/java/kamkeel/npcs/network/packets/request/ability/AbilitiesPlayerGetPacket.java @@ -0,0 +1,50 @@ +package kamkeel.npcs.network.packets.request.ability; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import kamkeel.npcs.network.AbstractPacket; +import kamkeel.npcs.network.PacketChannel; +import kamkeel.npcs.network.PacketHandler; +import kamkeel.npcs.network.PacketUtil; +import kamkeel.npcs.network.enums.EnumItemPacketType; +import kamkeel.npcs.network.enums.EnumRequestPacket; +import kamkeel.npcs.network.packets.data.large.GuiDataPacket; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.controllers.data.PlayerData; + +import java.io.IOException; + +public class AbilitiesPlayerGetPacket extends AbstractPacket { + public static final String packetName = "Request|PlayerDataAbilitiesGet"; + + public AbilitiesPlayerGetPacket() { + } + + @Override + public Enum getType() { + return EnumRequestPacket.PlayerDataAbilitiesGet; + } + + @Override + public PacketChannel getChannel() { + return PacketHandler.REQUEST_PACKET; + } + + @SideOnly(Side.CLIENT) + @Override + public void sendData(ByteBuf out) throws IOException { + } + + @Override + public void receiveData(ByteBuf in, EntityPlayer player) throws IOException { + if (!PacketUtil.verifyItemPacket(packetName, player, EnumItemPacketType.WAND)) + return; + + NBTTagCompound compound = new NBTTagCompound(); + PlayerData.get(player).abilities.writeToNBT(compound); + GuiDataPacket.sendGuiData((EntityPlayerMP) player, compound); + } +} diff --git a/src/main/java/kamkeel/npcs/network/packets/request/ability/AbilitiesPlayerSavePacket.java b/src/main/java/kamkeel/npcs/network/packets/request/ability/AbilitiesPlayerSavePacket.java new file mode 100644 index 000000000..998dcb383 --- /dev/null +++ b/src/main/java/kamkeel/npcs/network/packets/request/ability/AbilitiesPlayerSavePacket.java @@ -0,0 +1,65 @@ +package kamkeel.npcs.network.packets.request.ability; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import kamkeel.npcs.network.AbstractPacket; +import kamkeel.npcs.network.PacketChannel; +import kamkeel.npcs.network.PacketHandler; +import kamkeel.npcs.network.PacketUtil; +import kamkeel.npcs.network.enums.EnumItemPacketType; +import kamkeel.npcs.network.enums.EnumRequestPacket; +import kamkeel.npcs.util.ByteBufUtils; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.CustomNpcsPermissions; +import noppes.npcs.controllers.data.PlayerData; + +import java.io.IOException; + +public class AbilitiesPlayerSavePacket extends AbstractPacket { + public static final String packetName = "Request|PlayerDataAbilitiesSave"; + + private NBTTagCompound abilitiesData; + + public AbilitiesPlayerSavePacket() { + } + + public AbilitiesPlayerSavePacket(NBTTagCompound abilitiesData) { + this.abilitiesData = abilitiesData; + } + + @Override + public Enum getType() { + return EnumRequestPacket.PlayerDataAbilitiesSave; + } + + @Override + public PacketChannel getChannel() { + return PacketHandler.REQUEST_PACKET; + } + + @Override + public CustomNpcsPermissions.Permission getPermission() { + return CustomNpcsPermissions.NPC_ADVANCED_ABILITIES; + } + + @SideOnly(Side.CLIENT) + @Override + public void sendData(ByteBuf out) throws IOException { + NBTTagCompound compound = new NBTTagCompound(); + if (abilitiesData != null) { + compound = abilitiesData; + } + ByteBufUtils.writeNBT(out, compound); + } + + @Override + public void receiveData(ByteBuf in, EntityPlayer player) throws IOException { + if (!PacketUtil.verifyItemPacket(packetName, player, EnumItemPacketType.WAND)) + return; + + NBTTagCompound compound = ByteBufUtils.readNBT(in); + PlayerData.get(player).abilities.readFromNBT(compound); + } +} diff --git a/src/main/java/noppes/npcs/DataAbilities.java b/src/main/java/noppes/npcs/DataAbilities.java index 4e77611de..a749c8258 100644 --- a/src/main/java/noppes/npcs/DataAbilities.java +++ b/src/main/java/noppes/npcs/DataAbilities.java @@ -10,8 +10,14 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.DamageSource; +import noppes.npcs.api.ability.IAbility; +import noppes.npcs.api.ability.IAbilityHolder; +import noppes.npcs.api.ability.IDataAbilities; +import noppes.npcs.api.entity.IEntity; +import noppes.npcs.api.entity.IPlayer; import noppes.npcs.controllers.AnimationController; import noppes.npcs.controllers.data.Animation; +import noppes.npcs.controllers.data.PlayerData; import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.scripted.NpcAPI; import noppes.npcs.scripted.event.AbilityEvent; @@ -26,9 +32,9 @@ * Manages NPC abilities - storage, selection, execution, and cooldowns. * Follows the DataStats/DataAI pattern for NPC data management. */ -public class DataAbilities { +public class DataAbilities implements IDataAbilities { - private final EntityNPCInterface npc; + private final IAbilityHolder parent; private final Random random = new Random(); // ═══════════════════════════════════════════════════════════════════ @@ -67,8 +73,8 @@ public class DataAbilities { // CONSTRUCTOR // ═══════════════════════════════════════════════════════════════════ - public DataAbilities(EntityNPCInterface npc) { - this.npc = npc; + public DataAbilities(IAbilityHolder parent) { + this.parent = parent; } // ═══════════════════════════════════════════════════════════════════ @@ -80,7 +86,11 @@ public DataAbilities(EntityNPCInterface npc) { * Should be called every tick from onLivingUpdate(). */ public void tick() { - if (!enabled || npc.worldObj.isRemote || npc.isKilled()) { + if (!enabled || getEntity().worldObj.isRemote) { + return; + } + + if (isNpc() && getNpc().isKilled()) { return; } @@ -99,7 +109,7 @@ public void tick() { * Tick the currently executing ability. */ private void tickCurrentAbility() { - EntityLivingBase target = lastTarget != null ? lastTarget : npc.getAttackTarget(); + EntityLivingBase target = lastTarget != null ? lastTarget : getTarget(); AbilityPhase oldPhase = currentAbility.getPhase(); // Tick advances time and possibly changes phase @@ -111,7 +121,7 @@ private void tickCurrentAbility() { // Handle phase-specific logic switch (currentAbility.getPhase()) { case WINDUP: - currentAbility.onWindUpTick(npc, target, npc.worldObj, currentAbility.getCurrentTick()); + currentAbility.onWindUpTick(parent, target, getEntity().worldObj, currentAbility.getCurrentTick()); break; case ACTIVE: @@ -132,16 +142,16 @@ private void tickCurrentAbility() { // Fire execute event (cancelable) AbilityEvent.ExecuteEvent executeEvent = new AbilityEvent.ExecuteEvent( - npc.wrappedNPC, currentAbility, target); + parent, currentAbility, target); if (NpcAPI.EVENT_BUS.post(executeEvent)) { // Event was cancelled - skip execution but continue to recovery return; } // Call onExecute - currentAbility.onExecute(npc, target, npc.worldObj); + currentAbility.onExecute(parent, target, getEntity().worldObj); } - currentAbility.onActiveTick(npc, target, npc.worldObj, currentAbility.getCurrentTick()); + currentAbility.onActiveTick(parent, target, getEntity().worldObj, currentAbility.getCurrentTick()); break; case RECOVERY: @@ -150,11 +160,11 @@ private void tickCurrentAbility() { case IDLE: // Ability completed - currentAbility.onComplete(npc, target); + currentAbility.onComplete(parent, target); // Fire complete event AbilityEvent.CompleteEvent completeEvent = new AbilityEvent.CompleteEvent( - npc.wrappedNPC, currentAbility, target); + parent, currentAbility, target); NpcAPI.EVENT_BUS.post(completeEvent); onAbilityComplete(); @@ -166,13 +176,15 @@ private void tickCurrentAbility() { if (currentAbility != null && currentAbility.isExecuting()) { if (isAbilityControllingMovement()) { // Clear navigator so AI doesn't fight with ability movement - npc.getNavigator().clearPathEntity(); + if (isNpc()) { + getNpc().getNavigator().clearPathEntity(); + } // Only zero motion if lockMovement is true AND ability doesn't have its own movement // This allows stationary abilities to freeze the NPC, while movement abilities can set their own motion if (currentAbility.isLockMovement() && !currentAbility.hasAbilityMovement()) { - npc.motionX = 0; - npc.motionZ = 0; + getEntity().motionX = 0; + getEntity().motionZ = 0; } } } @@ -288,14 +300,14 @@ private boolean isAbilityEligible(Ability ability, EntityLivingBase target) { // Check range if (target != null) { - float distance = npc.getDistanceToEntity(target); + float distance = getEntity().getDistanceToEntity(target); if (distance < ability.getMinRange() || distance > ability.getMaxRange()) { return false; } } // Check conditions - if (!ability.checkConditions(npc, target)) { + if (!ability.checkConditions(parent, target)) { return false; } @@ -308,7 +320,7 @@ private boolean isAbilityEligible(Ability ability, EntityLivingBase target) { private boolean startAbility(Ability ability, EntityLivingBase target) { // Fire start event (cancelable) AbilityEvent.StartEvent startEvent = new AbilityEvent.StartEvent( - npc.wrappedNPC, ability, target); + parent, ability, target); if (NpcAPI.EVENT_BUS.post(startEvent)) { // Event was cancelled - don't start the ability return false; @@ -335,7 +347,7 @@ private boolean startAbility(Ability ability, EntityLivingBase target) { */ private void playAbilitySound(String sound) { if (sound != null && !sound.isEmpty()) { - npc.worldObj.playSoundAtEntity(npc, sound, 1.0f, 1.0f); + getEntity().worldObj.playSoundAtEntity(getEntity(), sound, 1.0f, 1.0f); } } @@ -348,9 +360,17 @@ private void playAbilityAnimation(int animationId) { Animation animation = AnimationController.Instance.animations.get(animationId); if (animation != null) { - npc.display.animationData.setEnabled(true); - npc.display.animationData.setAnimation(animation); - npc.display.animationData.updateClient(); + if (isNpc()) { + getNpc().display.animationData.setEnabled(true); + getNpc().display.animationData.setAnimation(animation); + getNpc().display.animationData.updateClient(); + } + + if (isPlayer()) { + getPlayer().animationData.setEnabled(true); + getPlayer().animationData.setAnimation(animation); + getPlayer().animationData.updateClient(); + } } } @@ -358,19 +378,26 @@ private void playAbilityAnimation(int animationId) { * Stop any currently playing ability animation. */ private void stopAbilityAnimation() { - npc.display.animationData.setAnimation(null); - npc.display.animationData.updateClient(); + if (isNpc()) { + getNpc().display.animationData.setAnimation(null); + getNpc().display.animationData.updateClient(); + } + + if (isPlayer()) { + getPlayer().animationData.setAnimation(null); + getPlayer().animationData.updateClient(); + } } /** * Spawn and send telegraph for an ability. */ private void spawnTelegraph(Ability ability, EntityLivingBase target) { - TelegraphInstance telegraph = ability.createTelegraph(npc, target); + TelegraphInstance telegraph = ability.createTelegraph(parent, target); if (telegraph != null) { ability.setTelegraphInstance(telegraph); // Send to all nearby players - TelegraphSpawnPacket.sendToTracking(telegraph, npc); + TelegraphSpawnPacket.sendToTracking(telegraph, getEntity()); } } @@ -380,7 +407,7 @@ private void spawnTelegraph(Ability ability, EntityLivingBase target) { private void removeTelegraph(Ability ability) { TelegraphInstance telegraph = ability.getTelegraphInstance(); if (telegraph != null) { - TelegraphRemovePacket.sendToTracking(telegraph.getInstanceId(), npc); + TelegraphRemovePacket.sendToTracking(telegraph.getInstanceId(), getEntity()); ability.setTelegraphInstance(null); } } @@ -397,14 +424,14 @@ public boolean isOnCooldown(Ability ability) { if (endTime == null) { return false; } - return npc.worldObj.getTotalWorldTime() < endTime; + return getEntity().worldObj.getTotalWorldTime() < endTime; } /** * Start cooldown for an ability. */ private void startCooldown(Ability ability) { - long endTime = npc.worldObj.getTotalWorldTime() + ability.getCooldownTicks(); + long endTime = getEntity().worldObj.getTotalWorldTime() + ability.getCooldownTicks(); cooldowns.put(ability.getId(), endTime); } @@ -415,14 +442,6 @@ public void resetCooldown(String abilityId) { cooldowns.remove(abilityId); } - /** - * Reset all cooldowns. - */ - public void resetAllCooldowns() { - cooldowns.clear(); - globalCooldownTimer = 0; - } - // ═══════════════════════════════════════════════════════════════════ // INTERRUPTION - Called from CombatHandler on damage // ═══════════════════════════════════════════════════════════════════ @@ -454,7 +473,7 @@ public boolean onDamage(DamageSource source, float amount) { * Record a hit for the hit count condition. */ private void recordHit() { - recentHitTimes.add(npc.worldObj.getTotalWorldTime()); + recentHitTimes.add(getEntity().worldObj.getTotalWorldTime()); } /** @@ -463,8 +482,9 @@ private void recordHit() { * @param withinTicks The time window in ticks * @return Number of hits in that window */ + @Override public int getRecentHitCount(int withinTicks) { - long currentTime = npc.worldObj.getTotalWorldTime(); + long currentTime = getEntity().worldObj.getTotalWorldTime(); long cutoff = currentTime - withinTicks; // Clean up old entries and count @@ -491,10 +511,10 @@ public void interruptCurrentAbility(DamageSource source, float damage) { // Fire interrupt event AbilityEvent.InterruptEvent interruptEvent = new AbilityEvent.InterruptEvent( - npc.wrappedNPC, currentAbility, lastTarget, source, damage); + parent, currentAbility, lastTarget, source, damage); NpcAPI.EVENT_BUS.post(interruptEvent); - currentAbility.onInterrupt(npc, source, damage); + currentAbility.onInterrupt(parent, source, damage); currentAbility.interrupt(); currentAbility = null; lastTarget = null; @@ -523,7 +543,7 @@ public void stopCurrentAbility() { */ private void fireTickEvent(Ability ability, EntityLivingBase target) { AbilityEvent.TickEvent event = new AbilityEvent.TickEvent( - npc.wrappedNPC, ability, target, + parent, ability, target, ability.getPhase().ordinal(), ability.getCurrentTick()); NpcAPI.EVENT_BUS.post(event); } @@ -544,7 +564,7 @@ public AbilityEvent.HitEvent fireHitEvent(Ability ability, EntityLivingBase targ EntityLivingBase hitEntity, float damage, float knockback, float knockbackUp) { AbilityEvent.HitEvent event = new AbilityEvent.HitEvent( - npc.wrappedNPC, ability, target, hitEntity, damage, knockback, knockbackUp); + parent, ability, target, hitEntity, damage, knockback, knockbackUp); if (NpcAPI.EVENT_BUS.post(event)) { return null; // Cancelled } @@ -554,8 +574,44 @@ public AbilityEvent.HitEvent fireHitEvent(Ability ability, EntityLivingBase targ /** * Get the NPC this DataAbilities belongs to. */ - public EntityNPCInterface getNpc() { - return npc; + public boolean isNpc() { + return parent instanceof EntityNPCInterface; + } + + public boolean isPlayer() { + return parent instanceof PlayerData; + } + + private EntityNPCInterface getNpc() { + return (EntityNPCInterface) parent; + } + + private PlayerData getPlayer() { + return (PlayerData) parent; + } + + public EntityLivingBase getEntity() { + if (isNpc()) + return (EntityNPCInterface) parent; + if (isPlayer()) + return ((PlayerData) parent).player; + return null; + } + + private EntityLivingBase getTarget() { + if (isNpc()) + return getNpc().getAttackTarget(); + + if (isPlayer() && currentAbility != null) { + IPlayer player = NoppesUtilServer.getIPlayer(getPlayer().player); + + IEntity[] entities = player.getLookingAtEntities(Math.round(currentAbility.getMaxRange()), 1, 1); + + if (entities.length > 0) + return (EntityLivingBase) entities[0]; + } + + return null; } // ═══════════════════════════════════════════════════════════════════ @@ -568,7 +624,7 @@ public EntityNPCInterface getNpc() { */ public void reset() { stopCurrentAbility(); - resetAllCooldowns(); + resetCooldowns(); // Reset execution state on all abilities for (Ability ability : abilities) { @@ -580,12 +636,24 @@ public void reset() { // ABILITY LIST MANAGEMENT // ═══════════════════════════════════════════════════════════════════ - public List getAbilities() { - return abilities; + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public IAbility[] getAbilities() { + return this.abilities.toArray(new IAbility[]{}); } - public void addAbility(Ability ability) { - abilities.add(ability); + @Override + public void addAbility(IAbility ability) { + abilities.add((Ability) ability); } public void removeAbility(int index) { @@ -594,11 +662,13 @@ public void removeAbility(int index) { } } + @Override public void removeAbility(String id) { abilities.removeIf(a -> a.getId().equals(id)); } - public Ability getAbility(String id) { + @Override + public IAbility getAbility(String id) { for (Ability ability : abilities) { if (ability.getId().equals(id)) { return ability; @@ -607,6 +677,12 @@ public Ability getAbility(String id) { return null; } + @Override + public boolean hasAbility(String abilityId) { + return false; + } + + @Override public void clearAbilities() { abilities.clear(); } @@ -626,9 +702,34 @@ public boolean isExecutingAbility() { return currentAbility != null && currentAbility.isExecuting(); } + @Override + public void interruptCurrentAbility() { + + } + + @Override + public int getGlobalCooldown() { + return 0; + } + + @Override + public void setGlobalCooldown(int ticks) { + + } + + /** + * Reset all cooldowns. + */ + @Override + public void resetCooldowns() { + cooldowns.clear(); + globalCooldownTimer = 0; + } + /** * Get the currently executing ability. */ + @Override public Ability getCurrentAbility() { return currentAbility; } diff --git a/src/main/java/noppes/npcs/controllers/data/PlayerData.java b/src/main/java/noppes/npcs/controllers/data/PlayerData.java index 599f81ff1..118c763cb 100644 --- a/src/main/java/noppes/npcs/controllers/data/PlayerData.java +++ b/src/main/java/noppes/npcs/controllers/data/PlayerData.java @@ -14,7 +14,10 @@ import net.minecraft.world.World; import net.minecraftforge.common.IExtendedEntityProperties; import noppes.npcs.CustomNpcs; +import noppes.npcs.DataAbilities; import noppes.npcs.LogWriter; +import noppes.npcs.api.ability.IAbilityHolder; +import noppes.npcs.api.ability.IDataAbilities; import noppes.npcs.api.entity.ICustomNpc; import noppes.npcs.api.handler.IPlayerBankData; import noppes.npcs.api.handler.IPlayerData; @@ -45,7 +48,7 @@ import java.util.HashSet; import java.util.UUID; -public class PlayerData implements IExtendedEntityProperties, IPlayerData { +public class PlayerData implements IExtendedEntityProperties, IPlayerData, IAbilityHolder { public PlayerDialogData dialogData = new PlayerDialogData(this); public PlayerBankData bankData = new PlayerBankData(this); public PlayerQuestData questData = new PlayerQuestData(this); @@ -58,6 +61,7 @@ public class PlayerData implements IExtendedEntityProperties, IPlayerData { public DataTimers timers = new DataTimers(this); public DataSkinOverlays skinOverlays = new DataSkinOverlays(this); public MagicData magicData = new MagicData(); + public DataAbilities abilities = new DataAbilities(this); public ActionManager actionManager = new ActionManager(); public PlayerDataScript scriptData; @@ -130,6 +134,7 @@ public void setNBT(NBTTagCompound data) { animationData.readFromNBT(data); effectData.readFromNBT(data); magicData.readToNBT(data); + abilities.readFromNBT(data); if (player != null) { playername = player.getCommandSenderName(); @@ -172,6 +177,7 @@ public NBTTagCompound getNBT() { animationData.writeToNBT(compound); effectData.writeToNBT(compound); magicData.writeToNBT(compound); + abilities.writeToNBT(compound); compound.setString("PlayerName", playername); compound.setString("UUID", uuid); @@ -445,6 +451,11 @@ public void load() { setNBT(data); } + @Override + public IDataAbilities getAbilityData() { + return (IDataAbilities) abilities; + } + public static PlayerData get(EntityPlayer player) { if (player.worldObj.isRemote) return CustomNpcs.proxy.getPlayerData(player); diff --git a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java index 702d27cd0..24f3ce30b 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java @@ -121,6 +121,8 @@ import noppes.npcs.ai.target.EntityAIClosestTarget; import noppes.npcs.ai.target.EntityAIOwnerHurtByTarget; import noppes.npcs.ai.target.EntityAIOwnerHurtTarget; +import noppes.npcs.api.ability.IAbilityHolder; +import noppes.npcs.api.ability.IDataAbilities; import noppes.npcs.api.entity.ICustomNpc; import noppes.npcs.api.handler.data.ILine; import noppes.npcs.api.item.IItemStack; @@ -171,7 +173,7 @@ import java.util.Iterator; import java.util.List; -public abstract class EntityNPCInterface extends EntityCreature implements IEntityAdditionalSpawnData, ICommandSender, IRangedAttackMob, IBossDisplayData { +public abstract class EntityNPCInterface extends EntityCreature implements IEntityAdditionalSpawnData, ICommandSender, IRangedAttackMob, IBossDisplayData, IAbilityHolder { public ICustomNpc wrappedNPC; public static final GameProfileAlt chateventProfile = new GameProfileAlt(); @@ -1118,6 +1120,11 @@ protected float getSoundPitch() { return super.getSoundPitch(); } + @Override + public IDataAbilities getAbilityData() { + return (IDataAbilities) abilities; + } + /** * Plays step sound at given x, y, z for the entity */ @@ -2147,7 +2154,7 @@ public void moveEntityWithHeading(float strafe, float forward) { protected boolean handleMountedMovement(float strafe, float forward) { return NPCMountUtil.handleMountedMovement(this, mountState, strafe, forward); } - + public void performMountedMovement(float strafe, float forward, float moveSpeed) { this.moveStrafing = strafe; this.moveForward = forward; diff --git a/src/main/java/noppes/npcs/scripted/event/AbilityEvent.java b/src/main/java/noppes/npcs/scripted/event/AbilityEvent.java index 9baf245a2..52e8a6f73 100644 --- a/src/main/java/noppes/npcs/scripted/event/AbilityEvent.java +++ b/src/main/java/noppes/npcs/scripted/event/AbilityEvent.java @@ -6,7 +6,7 @@ import net.minecraft.util.DamageSource; import noppes.npcs.api.IDamageSource; import noppes.npcs.api.ability.IAbility; -import noppes.npcs.api.entity.ICustomNpc; +import noppes.npcs.api.ability.IAbilityHolder; import noppes.npcs.api.entity.IEntityLivingBase; import noppes.npcs.api.event.IAbilityEvent; import noppes.npcs.constants.EnumScriptType; @@ -15,12 +15,13 @@ /** * Events fired during NPC ability execution lifecycle. */ -public class AbilityEvent extends NpcEvent implements IAbilityEvent { +public class AbilityEvent extends CustomNPCsEvent implements IAbilityEvent { protected final Ability ability; + protected final IAbilityHolder entity; protected final IEntityLivingBase target; - public AbilityEvent(ICustomNpc npc, Ability ability, EntityLivingBase target) { - super(npc); + public AbilityEvent(IAbilityHolder entity, Ability ability, EntityLivingBase target) { + this.entity = entity; this.ability = ability; this.target = target != null ? (IEntityLivingBase) NpcAPI.Instance().getIEntity(target) : null; } @@ -35,6 +36,11 @@ public IEntityLivingBase getTarget() { return target; } + @Override + public IAbilityHolder getEntity() { + return entity; + } + @Override public String getHookName() { return "abilityEvent"; @@ -45,8 +51,8 @@ public String getHookName() { */ @Cancelable public static class StartEvent extends AbilityEvent implements IAbilityEvent.StartEvent { - public StartEvent(ICustomNpc npc, Ability ability, EntityLivingBase target) { - super(npc, ability, target); + public StartEvent(IAbilityHolder entity, Ability ability, EntityLivingBase target) { + super(entity, ability, target); } @Override @@ -60,8 +66,8 @@ public String getHookName() { */ @Cancelable public static class ExecuteEvent extends AbilityEvent implements IAbilityEvent.ExecuteEvent { - public ExecuteEvent(ICustomNpc npc, Ability ability, EntityLivingBase target) { - super(npc, ability, target); + public ExecuteEvent(IAbilityHolder entity, Ability ability, EntityLivingBase target) { + super(entity, ability, target); } @Override @@ -77,8 +83,8 @@ public static class InterruptEvent extends AbilityEvent implements IAbilityEvent private final IDamageSource damageSource; private final float damage; - public InterruptEvent(ICustomNpc npc, Ability ability, EntityLivingBase target, DamageSource source, float damage) { - super(npc, ability, target); + public InterruptEvent(IAbilityHolder entity, Ability ability, EntityLivingBase target, DamageSource source, float damage) { + super(entity, ability, target); this.damageSource = NpcAPI.Instance().getIDamageSource(source); this.damage = damage; } @@ -103,8 +109,8 @@ public String getHookName() { * Fired when an ability completes its full execution cycle. */ public static class CompleteEvent extends AbilityEvent implements IAbilityEvent.CompleteEvent { - public CompleteEvent(ICustomNpc npc, Ability ability, EntityLivingBase target) { - super(npc, ability, target); + public CompleteEvent(IAbilityHolder entity, Ability ability, EntityLivingBase target) { + super(entity, ability, target); } @Override @@ -124,9 +130,9 @@ public static class HitEvent extends AbilityEvent implements IAbilityEvent.HitEv private float knockback; private float knockbackUp; - public HitEvent(ICustomNpc npc, Ability ability, EntityLivingBase target, + public HitEvent(IAbilityHolder entity, Ability ability, EntityLivingBase target, EntityLivingBase hitEntity, float damage, float knockback, float knockbackUp) { - super(npc, ability, target); + super(entity, ability, target); this.hitEntity = hitEntity != null ? (IEntityLivingBase) NpcAPI.Instance().getIEntity(hitEntity) : null; this.damage = damage; this.knockback = knockback; @@ -182,8 +188,8 @@ public static class TickEvent extends AbilityEvent implements IAbilityEvent.Tick private final int abilityPhase; private final int tick; - public TickEvent(ICustomNpc npc, Ability ability, EntityLivingBase target, int phase, int tick) { - super(npc, ability, target); + public TickEvent(IAbilityHolder entity, Ability ability, EntityLivingBase target, int phase, int tick) { + super(entity, ability, target); this.abilityPhase = phase; this.tick = tick; }