mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 19:34:09 +00:00
Add Ignore I-Frames to Abilities
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user