Add Ignore I-Frames to Abilities

This commit is contained in:
Kam committed 2026-03-02 03:58:18 -05:00
1 parent f6a8edfef1
commit a077c7b32f
14 files changed
+175 -160

No files matched your search

@@ -85,6 +85,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
// Interruption
protected boolean interruptible = true;
protected InvulnerableMode invulnerableMode = InvulnerableMode.NONE;
protected boolean ignoreIFrames = false;
// Feedback
protected LockMode lockMovement = LockMode.WINDUP;
@@ -365,22 +366,11 @@ public abstract class Ability implements IAbility, IAbilityAction {
return true;
}
public void onWindUpTick(EntityLivingBase caster, EntityLivingBase target, int tick) {
}
public void onWindUpTick(EntityLivingBase caster, EntityLivingBase target, int tick) {}
/**
* Whether this execution is a burst refire (not the first execution).
* Useful in onExecute() to detect when windup was skipped and entities need fresh creation.
*/
public boolean isBurstRefire() {
return burstEnabled && burstIndex > 0;
}
public void onInterrupt(EntityLivingBase caster, DamageSource source, float damage) {}
public void onInterrupt(EntityLivingBase caster, DamageSource source, float damage) {
}
public void onComplete(EntityLivingBase caster, EntityLivingBase target) {
}
public void onComplete(EntityLivingBase caster, EntityLivingBase target) {}
/**
* Called when the ability enters BURST_DELAY between burst iterations.
@@ -409,24 +399,6 @@ public abstract class Ability implements IAbility, IAbilityAction {
return applyAbilityDamageInternal(caster, hitEntity, damage, knockback, 0.0f, dx, dz);
}
/**
* Apply damage to an entity with ability hit event support and vertical knockback.
* Fires the abilityHit script event, allowing scripts to modify or cancel the damage.
*
* @param caster The entity executing the ability (NPC or Player)
* @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(EntityLivingBase caster, EntityLivingBase hitEntity,
float damage, float knockback, float knockbackUp) {
double dx = hitEntity.posX - caster.posX;
double dz = hitEntity.posZ - caster.posZ;
return applyAbilityDamageInternal(caster, hitEntity, damage, knockback, knockbackUp, dx, dz);
}
/**
* 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.
@@ -445,6 +417,28 @@ public abstract class Ability implements IAbility, IAbilityAction {
return applyAbilityDamageInternal(caster, hitEntity, damage, knockback, 0.0f, knockbackDirX, knockbackDirZ);
}
/**
* Clears hurt resistance before damage and returns the previous value so it can be restored later.
*/
public static int clearHurtResistanceIfNeeded(EntityLivingBase target, boolean ignoreIFrames) {
if (!ignoreIFrames || target == null) {
return -1;
}
int previous = target.hurtResistantTime;
target.hurtResistantTime = 0;
return previous;
}
/**
* Restores hurt resistance after damage when {@link #clearHurtResistanceIfNeeded} was used.
*/
public static void restoreHurtResistanceIfNeeded(EntityLivingBase target, boolean ignoreIFrames, int previous) {
if (!ignoreIFrames || target == null || previous < 0) {
return;
}
target.hurtResistantTime = previous;
}
/**
* Internal unified damage application method.
* All public damage methods delegate to this.
@@ -470,19 +464,24 @@ public abstract class Ability implements IAbility, IAbilityAction {
// Apply damage
if (damage > 0) {
// Check for ability extenders (e.g., DBC Addon damage routing)
boolean handled = AbilityController.Instance.fireOnAbilityDamage(
this, caster, hitEntity, damage, knockback, knockbackUp,
knockbackDirX, knockbackDirZ, 1.0f);
if (!handled) {
// Default damage path
if (caster instanceof EntityNPCInterface) {
hitEntity.attackEntityFrom(new NpcDamageSource("mob", (EntityNPCInterface) caster), damage);
} else if (caster instanceof EntityPlayer) {
hitEntity.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) caster), damage);
} else {
hitEntity.attackEntityFrom(DamageSource.causeMobDamage(caster), damage);
int previousHurtResistantTime = clearHurtResistanceIfNeeded(hitEntity, ignoreIFrames);
try {
// Check for ability extenders (e.g., DBC Addon damage routing)
boolean handled = AbilityController.Instance.fireOnAbilityDamage(
this, caster, hitEntity, damage, knockback, knockbackUp,
knockbackDirX, knockbackDirZ, 1.0f);
if (!handled) {
// Default damage path
if (caster instanceof EntityNPCInterface) {
hitEntity.attackEntityFrom(new NpcDamageSource("mob", (EntityNPCInterface) caster), damage);
} else if (caster instanceof EntityPlayer) {
hitEntity.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) caster), damage);
} else {
hitEntity.attackEntityFrom(DamageSource.causeMobDamage(caster), damage);
}
}
} finally {
restoreHurtResistanceIfNeeded(hitEntity, ignoreIFrames, previousHurtResistantTime);
}
}
@@ -591,14 +590,6 @@ public abstract class Ability implements IAbility, IAbilityAction {
return null;
}
/**
* Returns true if the telegraph type for this ability is locked and cannot be changed.
* Telegraph type is inherent to how the ability works (e.g., Charge uses LINE, Slam uses CIRCLE).
*/
public boolean isTelegraphTypeLocked() {
return true;
}
/**
* Add field definitions for this ability's GUI.
* Override in subclasses to add type-specific fields. The list already contains
@@ -716,6 +707,10 @@ public abstract class Ability implements IAbility, IAbilityAction {
})
.hover("ability.hover.invulnerable")
.tab("General"));
defs.add(FieldDef.boolField("ability.ignoreIFrames", this::isIgnoreIFrames, this::setIgnoreIFrames)
.hover("ability.hover.ignoreIFrames")
.visibleWhen(this::hasDamage)
.tab("General"));
// ── Burst section ────────────────────────────────────────────
if (allowBurst()) {
@@ -1035,43 +1030,6 @@ public abstract class Ability implements IAbility, IAbilityAction {
return startY - 0.5;
}
/**
* Calculates offset position near the given coordinates.
* Used to place effects near a target rather than exactly on them.
*
* @param baseX Base X coordinate
* @param baseY Base Y coordinate
* @param baseZ Base Z coordinate
* @param minOffset Minimum offset distance
* @param maxOffset Maximum offset distance
* @param randomOffset Whether to use random offset within range, or fixed at max
* @param random Random instance to use
* @return Array of [x, y, z] with offset applied
*/
public static double[] calculateOffsetPosition(double baseX, double baseY, double baseZ,
float minOffset, float maxOffset,
boolean randomOffset, java.util.Random random) {
if (maxOffset <= 0) {
return new double[]{baseX, baseY, baseZ};
}
double offsetDist;
double offsetAngle;
if (randomOffset) {
offsetDist = minOffset + random.nextDouble() * (maxOffset - minOffset);
offsetAngle = random.nextDouble() * Math.PI * 2;
} else {
offsetDist = maxOffset;
offsetAngle = random.nextDouble() * Math.PI * 2;
}
double offsetX = Math.cos(offsetAngle) * offsetDist;
double offsetZ = Math.sin(offsetAngle) * offsetDist;
return new double[]{baseX + offsetX, baseY, baseZ + offsetZ};
}
/**
* Get the current telegraph instances.
*/
@@ -1426,6 +1384,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
nbt.setInteger("recovery", dazedTicks);
nbt.setBoolean("interruptible", interruptible);
nbt.setInteger("invulnerableMode", invulnerableMode.ordinal());
nbt.setBoolean("ignoreIFrames", ignoreIFrames);
nbt.setInteger("lockMovement", lockMovement.ordinal());
nbt.setInteger("rotationMode", rotationMode.ordinal());
nbt.setInteger("rotationPhase", rotationPhase.ordinal());
@@ -1519,6 +1478,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
invulnerableMode = nbt.hasKey("invulnerableMode")
? InvulnerableMode.fromOrdinal(nbt.getInteger("invulnerableMode"))
: InvulnerableMode.NONE;
ignoreIFrames = nbt.hasKey("ignoreIFrames") && nbt.getBoolean("ignoreIFrames");
lockMovement = LockMode.fromOrdinal(nbt.getInteger("lockMovement"));
rotationMode = RotationMode.fromOrdinal(nbt.getInteger("rotationMode"));
rotationPhase = LockMode.fromOrdinal(nbt.getInteger("rotationPhase"));
@@ -1823,6 +1783,16 @@ public abstract class Ability implements IAbility, IAbilityAction {
return invulnerableMode.invulnerableDuringActive();
}
@Override
public boolean isIgnoreIFrames() {
return ignoreIFrames;
}
@Override
public void setIgnoreIFrames(boolean ignore) {
this.ignoreIFrames = ignore;
}
public LockMode getLockMovement() {
return lockMovement;
}
@@ -20,7 +20,6 @@ public class AbilityHazard extends AbilityZone implements IAbilityHazard {
private float radius = 2.0f;
private float damagePerSecond = 1.0f;
private int damageInterval = 20;
private boolean ignoreInvulnFrames = false;
private boolean affectsCaster = false;
public AbilityHazard() {
@@ -75,7 +74,7 @@ public class AbilityHazard extends AbilityZone implements IAbilityHazard {
zoneShape,
radius,
damagePerSecond, damageInterval,
ignoreInvulnFrames, affectsCaster,
isIgnoreIFrames(), affectsCaster,
durationTicks,
colorData.innerColor, colorData.outerColor, colorData.outerColorEnabled,
zoneHeight,
@@ -99,7 +98,6 @@ public class AbilityHazard extends AbilityZone implements IAbilityHazard {
nbt.setFloat("radius", radius);
nbt.setFloat("damagePerSecond", damagePerSecond);
nbt.setInteger("damageInterval", damageInterval);
nbt.setBoolean("ignoreInvulnFrames", ignoreInvulnFrames);
nbt.setBoolean("affectsCaster", affectsCaster);
}
@@ -109,7 +107,6 @@ public class AbilityHazard extends AbilityZone implements IAbilityHazard {
this.radius = nbt.getFloat("radius");
this.damagePerSecond = nbt.getFloat("damagePerSecond");
this.damageInterval = nbt.getInteger("damageInterval");
this.ignoreInvulnFrames = nbt.getBoolean("ignoreInvulnFrames");
this.affectsCaster = nbt.getBoolean("affectsCaster");
}
@@ -137,14 +134,6 @@ public class AbilityHazard extends AbilityZone implements IAbilityHazard {
this.damageInterval = damageInterval;
}
public boolean isIgnoreInvulnFrames() {
return ignoreInvulnFrames;
}
public void setIgnoreInvulnFrames(boolean ignoreInvulnFrames) {
this.ignoreInvulnFrames = ignoreInvulnFrames;
}
public boolean isAffectsCaster() {
return affectsCaster;
}
@@ -176,7 +165,6 @@ public class AbilityHazard extends AbilityZone implements IAbilityHazard {
FieldDef.floatField("gui.dps", this::getDamagePerSecond, this::setDamagePerSecond),
FieldDef.intField("gui.interval", this::getDamageInterval, this::setDamageInterval)
),
FieldDef.boolField("ability.ignoreInvulnFrames", this::isIgnoreInvulnFrames, this::setIgnoreInvulnFrames),
FieldDef.boolField("ability.affectsCaster", this::isAffectsCaster, this::setAffectsCaster)
.hover("ability.hover.affectsCaster"),
AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects)
@@ -80,6 +80,7 @@ public class AbilityTrap extends AbilityZone implements IAbilityTrap {
zoneShape,
triggerRadius, armTime, maxTriggers, triggerCooldown,
damage, damageRadius, knockback, durationTicks,
isIgnoreIFrames(),
colorData.innerColor, colorData.outerColor, colorData.outerColorEnabled,
zoneHeight,
particleDensity, particleScale, animSpeed, lightningDensity,
@@ -263,7 +263,6 @@ public class AbilityVortex extends Ability implements IAbilityVortex {
state.lastZ = entity.posZ;
if (shouldDealPullDamage) {
entity.hurtResistantTime = 0;
applyAbilityDamage(caster, entity, pullDamage * 0.5f, 0);
}
}
@@ -212,6 +212,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
E entity = createEntity(caster, target, spawnPos, resolved, index);
entity.setAnchorData(projectiles[index].anchor);
entity.setEffects(this.effects);
entity.setIgnoreIFrames(this.isIgnoreIFrames());
entity.setSourceAbility(this);
return entity;
}
@@ -104,6 +104,8 @@ public class AbilitySweeper extends AbilityEnergy implements IAbilitySweeper {
sweepSpeed, numberOfRotations,
damage, damageInterval, piercing,
lockOnTarget);
activeEntity.setIgnoreIFrames(this.isIgnoreIFrames());
activeEntity.setSourceAbility(this);
if (isPreview()) {
activeEntity.setupPreview(caster);
@@ -156,7 +156,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
private float damagePerSecond = 1.0f;
private int damageInterval = 20;
private boolean ignoreInvulnFrames = false;
private boolean ignoreIFrames = false;
private boolean affectsCaster = false;
// ═══════════════════════════════════════════════════════════════════
@@ -203,6 +203,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
float triggerRadius, int armTime, int maxTriggers,
int triggerCooldown, float damage, float damageRadius,
float knockback, int durationTicks,
boolean ignoreIFrames,
int innerColor, int outerColor, boolean outerColorEnabled,
float zoneHeight,
float particleDensity, float particleScale,
@@ -221,6 +222,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
zone.knockback = knockback;
zone.durationTicks = durationTicks;
zone.maxTicks = durationTicks;
zone.ignoreIFrames = ignoreIFrames;
zone.innerColor = innerColor;
zone.outerColor = outerColor;
zone.outerColorEnabled = outerColorEnabled;
@@ -244,7 +246,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
ZoneShape shape,
float radius,
float damagePerSecond, int damageInterval,
boolean ignoreInvulnFrames, boolean affectsCaster,
boolean ignoreIFrames, boolean affectsCaster,
int durationTicks,
int innerColor, int outerColor, boolean outerColorEnabled,
float zoneHeight,
@@ -256,7 +258,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
zone.radius = radius;
zone.damagePerSecond = damagePerSecond;
zone.damageInterval = damageInterval;
zone.ignoreInvulnFrames = ignoreInvulnFrames;
zone.ignoreIFrames = ignoreIFrames;
zone.affectsCaster = affectsCaster;
zone.durationTicks = durationTicks;
zone.maxTicks = durationTicks;
@@ -472,9 +474,6 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
if (!isInZone(entity)) continue;
if (damagePerSecond > 0) {
if (ignoreInvulnFrames) {
entity.hurtResistantTime = 0;
}
applyDamage(entity, owner, damagePerSecond);
}
@@ -504,14 +503,19 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
private boolean applyDamage(EntityLivingBase target, Entity owner, float dmg) {
if (dmg <= 0) return false;
if (owner instanceof EntityNPCInterface) {
return target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), dmg);
} else if (owner instanceof EntityPlayer) {
return target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), dmg);
} else if (owner instanceof EntityLivingBase) {
return target.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) owner), dmg);
} else {
return target.attackEntityFrom(new NpcDamageSource("npc_ability", null), dmg);
int previousHurtResistantTime = Ability.clearHurtResistanceIfNeeded(target, ignoreIFrames);
try {
if (owner instanceof EntityNPCInterface) {
return target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), dmg);
} else if (owner instanceof EntityPlayer) {
return target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), dmg);
} else if (owner instanceof EntityLivingBase) {
return target.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) owner), dmg);
} else {
return target.attackEntityFrom(new NpcDamageSource("npc_ability", null), dmg);
}
} finally {
Ability.restoreHurtResistanceIfNeeded(target, ignoreIFrames, previousHurtResistantTime);
}
}
@@ -43,6 +43,7 @@ public abstract class EntityEnergyAbility extends Entity implements IEntityAddit
* The ability that spawned this entity. Transient, not saved to NBT.
*/
protected transient Ability sourceAbility = null;
protected boolean ignoreIFrames = false;
protected boolean previewMode = false;
protected EntityLivingBase previewOwner = null;
@@ -140,6 +141,14 @@ public abstract class EntityEnergyAbility extends Entity implements IEntityAddit
this.sourceAbility = ability;
}
public boolean isIgnoreIFrames() {
return ignoreIFrames;
}
public void setIgnoreIFrames(boolean ignoreIFrames) {
this.ignoreIFrames = ignoreIFrames;
}
// ==================== PREVIEW MODE ====================
public boolean isPreviewMode() {
@@ -313,6 +322,7 @@ public abstract class EntityEnergyAbility extends Entity implements IEntityAddit
*/
protected void writeEnergyBaseNBT(NBTTagCompound nbt) {
nbt.setInteger("OwnerId", ownerEntityId);
nbt.setBoolean("IgnoreIFrames", ignoreIFrames);
displayData.writeNBT(nbt);
lightningData.writeNBT(nbt);
}
@@ -323,6 +333,7 @@ public abstract class EntityEnergyAbility extends Entity implements IEntityAddit
*/
protected void readEnergyBaseNBT(NBTTagCompound nbt) {
this.ownerEntityId = nbt.getInteger("OwnerId");
this.ignoreIFrames = nbt.getBoolean("IgnoreIFrames");
displayData.readNBT(nbt);
lightningData.readNBT(nbt);
}
@@ -2,6 +2,7 @@ package kamkeel.npcs.entity;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.controllers.data.ability.Ability;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyBarrierData;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyDisplayData;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyLightningData;
@@ -206,6 +207,7 @@ public class EntityEnergyPanel extends EntityEnergyBarrier {
@SuppressWarnings("unchecked")
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, hitBox);
Entity owner = getOwnerEntity();
boolean ignoreIFrames = sourceAbility != null && sourceAbility.isIgnoreIFrames();
for (EntityLivingBase target : entities) {
if (target.getEntityId() == ownerEntityId) continue;
@@ -213,12 +215,17 @@ public class EntityEnergyPanel extends EntityEnergyBarrier {
// Apply damage
if (panelData.launchDamage > 0) {
if (owner instanceof EntityNPCInterface) {
target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), panelData.launchDamage);
} else if (owner instanceof EntityPlayer) {
target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), panelData.launchDamage);
} else {
target.attackEntityFrom(DamageSource.generic, panelData.launchDamage);
int previousHurtResistantTime = Ability.clearHurtResistanceIfNeeded(target, ignoreIFrames);
try {
if (owner instanceof EntityNPCInterface) {
target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), panelData.launchDamage);
} else if (owner instanceof EntityPlayer) {
target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), panelData.launchDamage);
} else {
target.attackEntityFrom(DamageSource.generic, panelData.launchDamage);
}
} finally {
Ability.restoreHurtResistanceIfNeeded(target, ignoreIFrames, previousHurtResistantTime);
}
}
@@ -3,6 +3,7 @@ package kamkeel.npcs.entity;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.controllers.AbilityController;
import kamkeel.npcs.controllers.data.ability.Ability;
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityEnergyProjectile;
import kamkeel.npcs.controllers.data.ability.data.effect.AbilityPotionEffect;
import kamkeel.npcs.controllers.data.ability.enums.AnchorPoint;
@@ -895,23 +896,24 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
// ==================== DAMAGE & EFFECTS ====================
protected void applyDamage(EntityLivingBase target) {
if (previewMode) return; // Skip damage in preview mode
applyDamage(target, this.getDamage(), this.getKnockback());
protected boolean applyDamage(EntityLivingBase target) {
if (previewMode) return false; // Skip damage in preview mode
return applyDamage(target, this.getDamage(), this.getKnockback());
}
protected void applyDamage(EntityLivingBase target, float dmg, float kb) {
if (previewMode) return; // Skip damage in preview mode
if (target == null || shouldIgnoreEntity(target)) return;
protected boolean applyDamage(EntityLivingBase target, float dmg, float kb) {
if (previewMode) return false; // Skip damage in preview mode
if (target == null || shouldIgnoreEntity(target)) return false;
// Fire entity impact event (may cancel or modify damage)
if (!worldObj.isRemote) {
float result = EventHooks.onEnergyProjectileEntityImpact(this, target, dmg);
if (result < 0) return; // Event was cancelled
if (result < 0) return false; // Event was cancelled
dmg = result;
}
Entity owner = getOwnerEntity();
boolean ignoreIFrames = isIgnoreIFrames();
// Check for ability extenders (e.g., DBC Addon damage routing)
boolean handled = false;
@@ -925,21 +927,26 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
dmg, kb, kbUp, dx, dz, damageMultiplier);
}
if (!handled) {
// Default damage path
if (owner instanceof EntityNPCInterface) {
defaultDamageApplied = target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), dmg);
} else if (owner instanceof EntityPlayer) {
defaultDamageApplied = target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), dmg);
} else if (owner instanceof EntityLivingBase) {
defaultDamageApplied = target.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) owner), dmg);
} else {
defaultDamageApplied = target.attackEntityFrom(new NpcDamageSource("npc_ability", null), dmg);
int previousHurtResistantTime = Ability.clearHurtResistanceIfNeeded(target, ignoreIFrames);
try {
if (!handled) {
// Default damage path
if (owner instanceof EntityNPCInterface) {
defaultDamageApplied = target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), dmg);
} else if (owner instanceof EntityPlayer) {
defaultDamageApplied = target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), dmg);
} else if (owner instanceof EntityLivingBase) {
defaultDamageApplied = target.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) owner), dmg);
} else {
defaultDamageApplied = target.attackEntityFrom(new NpcDamageSource("npc_ability", null), dmg);
}
}
} finally {
Ability.restoreHurtResistanceIfNeeded(target, ignoreIFrames, previousHurtResistantTime);
}
boolean allowSecondaryEffects = handled || dmg <= 0 || defaultDamageApplied;
if (!allowSecondaryEffects) return;
if (!allowSecondaryEffects) return false;
if (kb > 0) {
double dx = target.posX - posX;
@@ -955,6 +962,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
}
applyEffects(target);
return true;
}
protected void applyEffects(EntityLivingBase target) {
@@ -982,11 +990,11 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
}
}
protected void doExplosion() {
if (previewMode) return; // Skip explosion in preview mode
if (worldObj.isRemote) return; // Explosions are server-side only
protected boolean doExplosion() {
if (previewMode) return false; // Skip explosion in preview mode
if (worldObj.isRemote) return false; // Explosions are server-side only
float explosionRad = getExplosionRadius();
if (Float.isNaN(explosionRad) || explosionRad <= 0) return;
if (Float.isNaN(explosionRad) || explosionRad <= 0) return false;
final double explosionRadSq = explosionRad * explosionRad;
final float baseDamage = getDamage();
final float baseKnockback = getKnockback();
@@ -1004,6 +1012,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
@SuppressWarnings("unchecked")
List<EntityLivingBase> targets = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, explosionBox);
boolean anyDamaged = false;
for (EntityLivingBase target : targets) {
if (target == owner) continue;
@@ -1028,10 +1037,13 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
float dist = (float) Math.sqrt(distSq);
falloff = 1.0f - (dist / explosionRad) * damageFalloff;
}
applyDamage(target, baseDamage * falloff, baseKnockback * falloff);
if (applyDamage(target, baseDamage * falloff, baseKnockback * falloff)) {
anyDamaged = true;
}
}
tryDestroyTerrain(explosionRad);
return anyDamaged;
}
/**
@@ -2114,7 +2126,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
protected boolean processEntityHit(EntityLivingBase entity, double impactX, double impactY, double impactZ) {
if (entity == null || shouldIgnoreEntity(entity) || !canHitEntityNow(entity)) return false;
recordEntityHit(entity);
boolean successfulHit;
if (isExplosive()) {
Vec3 impactPoint = resolveEntityImpactPoint(entity, impactX, impactY, impactZ);
double oldX = posX;
@@ -2123,15 +2135,19 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
posX = impactPoint.xCoord;
posY = impactPoint.yCoord;
posZ = impactPoint.zCoord;
doExplosion();
successfulHit = doExplosion();
posX = oldX;
posY = oldY;
posZ = oldZ;
} else {
applyDamage(entity);
successfulHit = applyDamage(entity);
}
if (shouldTerminateAfterHit()) {
if (successfulHit) {
recordEntityHit(entity);
}
if ((successfulHit && shouldTerminateAfterHit()) || (!successfulHit && combatData.hitType == HitType.SINGLE)) {
hasHit = true;
this.setDead();
return true;
@@ -2,6 +2,7 @@ package kamkeel.npcs.entity;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.controllers.data.ability.Ability;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyDisplayData;
import kamkeel.npcs.util.CNPCDebug;
import net.minecraft.entity.Entity;
@@ -308,14 +309,20 @@ public class EntityEnergySweeper extends EntityEnergyAbility {
}
private void applyDamage(EntityLivingBase target, Entity owner) {
if (owner instanceof EntityNPCInterface) {
target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), damage);
} else if (owner instanceof EntityPlayer) {
target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), damage);
} else if (owner instanceof EntityLivingBase) {
target.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) owner), damage);
} else {
target.attackEntityFrom(new NpcDamageSource("npc_ability", null), damage);
boolean ignoreIFrames = isIgnoreIFrames();
int previousHurtResistantTime = Ability.clearHurtResistanceIfNeeded(target, ignoreIFrames);
try {
if (owner instanceof EntityNPCInterface) {
target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), damage);
} else if (owner instanceof EntityPlayer) {
target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), damage);
} else if (owner instanceof EntityLivingBase) {
target.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) owner), damage);
} else {
target.attackEntityFrom(new NpcDamageSource("npc_ability", null), damage);
}
} finally {
Ability.restoreHurtResistanceIfNeeded(target, ignoreIFrames, previousHurtResistantTime);
}
// Small upward knockback to help escape
@@ -120,4 +120,12 @@ public abstract class ScriptEnergyAbility<T extends EntityEnergyAbility> extends
public float getChargeProgress() {
return entity.getChargeProgress();
}
public boolean isIgnoreIFrames() {
return entity.isIgnoreIFrames();
}
public void setIgnoreIFrames(boolean ignore) {
entity.setIgnoreIFrames(ignore);
}
}