diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCounter.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCounter.java index 9c6299356..f0d5ab4b6 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCounter.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCounter.java @@ -2,12 +2,17 @@ package kamkeel.npcs.controllers.data.ability.type; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; +import kamkeel.npcs.addon.DBCAddon; +import noppes.npcs.controllers.AnimationController; import kamkeel.npcs.controllers.data.ability.enums.UserType; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; +import noppes.npcs.NpcDamageSource; +import noppes.npcs.controllers.data.Animation; +import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilityCounter; import noppes.npcs.client.gui.builder.FieldDef; @@ -55,38 +60,35 @@ public class AbilityCounter extends AbilityDefend implements IAbilityCounter { } } - private transient boolean counterTriggered; - // ═══════════════════════════════════════════════════════════════════ // DEFEND HOOKS // ═══════════════════════════════════════════════════════════════════ @Override - protected void onDefendTick(EntityLivingBase caster, EntityLivingBase target, int tick) { - if (counterTriggered && lastAttacker != null && lastAttacker.isEntityAlive()) { - counterTriggered = false; - - // Calculate counter damage - float damage; - if (counterType == CounterType.FLAT) { - damage = counterValue; - } else { - damage = lastDamageTaken * (counterValue / 100.0f); - } - - // Hit back - DamageSource counterSource = caster instanceof EntityPlayer - ? DamageSource.causePlayerDamage((EntityPlayer) caster) - : DamageSource.causeMobDamage(caster); - lastAttacker.attackEntityFrom(counterSource, damage); - - signalCompletion(); + protected float performDefend(EntityLivingBase attacker, float amount) { + // Calculate counter damage + float damage; + if (counterType == CounterType.FLAT) { + damage = counterValue; + } else { + damage = amount * (counterValue / 100.0f); + } + + // Hit back + if (caster != null && attacker.isEntityAlive()) { + if (caster instanceof EntityNPCInterface && DBCAddon.instance.canDBCAttack((EntityNPCInterface) caster, damage, attacker)) { + // NPC with DBC: dummy hit for events/knockback, then apply DBC damage with NPC's stats + attacker.attackEntityFrom(new NpcDamageSource("mob", (EntityNPCInterface) caster), 0.001f); + DBCAddon.instance.doDBCDamage((EntityNPCInterface) caster, damage, attacker); + } else { + // Player or non-DBC NPC: normal damage + DamageSource counterSource = caster instanceof EntityPlayer + ? DamageSource.causePlayerDamage((EntityPlayer) caster) + : DamageSource.causeMobDamage(caster); + attacker.attackEntityFrom(counterSource, damage); + } } - } - @Override - protected float performDefend(float amount) { - counterTriggered = true; return 0; } @@ -99,6 +101,22 @@ public class AbilityCounter extends AbilityDefend implements IAbilityCounter { return true; } + @Override + protected Animation getDefendAnimation() { + return getCounterAnimation(); + } + + public Animation getCounterAnimation() { + if (AnimationController.Instance == null) return null; + if (counterAnimationId >= 0) { + return (Animation) AnimationController.Instance.get(counterAnimationId); + } + if (counterAnimationName != null && !counterAnimationName.isEmpty()) { + return (Animation) AnimationController.Instance.get(counterAnimationName, true); + } + return null; + } + // ═══════════════════════════════════════════════════════════════════ // NBT // ═══════════════════════════════════════════════════════════════════ diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDefend.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDefend.java index 1a3451285..c9f6e1e0a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDefend.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDefend.java @@ -12,6 +12,7 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import noppes.npcs.api.ability.type.IAbilityDefend; import noppes.npcs.client.gui.builder.FieldDef; +import noppes.npcs.controllers.data.Animation; import java.util.List; @@ -19,7 +20,7 @@ import java.util.List; * Abstract base class for defensive abilities (Guard, Counter, Dodge). *
* {@link #onDefend} handles shared checks (physical melee only) then delegates
- * to {@link #performDefend(float)} which subclasses override for their specific behavior.
+ * to {@link #performDefend(EntityLivingBase, float)} which subclasses override for their specific behavior.
*/
public abstract class AbilityDefend extends Ability implements IAbilityDefend {
@@ -34,9 +35,12 @@ public abstract class AbilityDefend extends Ability implements IAbilityDefend {
// TRANSIENT RUNTIME STATE
// ═══════════════════════════════════════════════════════════════════
+ protected transient EntityLivingBase caster;
protected transient int hitCount;
protected transient EntityLivingBase lastAttacker;
protected transient float lastDamageTaken;
+ protected transient Animation pendingDefendAnimation;
+ protected transient int defendAnimEndTick = -1;
// ═══════════════════════════════════════════════════════════════════
// CONSTRUCTOR DEFAULTS
@@ -57,16 +61,14 @@ public abstract class AbilityDefend extends Ability implements IAbilityDefend {
@Override
public void onExecute(EntityLivingBase caster, EntityLivingBase target) {
+ this.caster = caster;
hitCount = 0;
lastAttacker = null;
lastDamageTaken = 0.0f;
- onDefendStart(caster);
}
@Override
public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, int tick) {
- onDefendTick(caster, target, tick);
-
if (tick >= durationTicks) {
signalCompletion();
}
@@ -75,9 +77,12 @@ public abstract class AbilityDefend extends Ability implements IAbilityDefend {
@Override
public void reset() {
super.reset();
+ caster = null;
hitCount = 0;
lastAttacker = null;
lastDamageTaken = 0.0f;
+ pendingDefendAnimation = null;
+ defendAnimEndTick = -1;
}
// ═══════════════════════════════════════════════════════════════════
@@ -107,7 +112,10 @@ public abstract class AbilityDefend extends Ability implements IAbilityDefend {
lastDamageTaken = amount;
hitCount++;
- float result = performDefend(amount);
+ float result = performDefend(attacker, amount);
+
+ // Queue defend reaction animation (played on next tick by AbstractDataAbilities)
+ pendingDefendAnimation = getDefendAnimation();
// Auto-complete after max hits
if (maxHitAmount > 0 && hitCount >= maxHitAmount) {
@@ -120,19 +128,16 @@ public abstract class AbilityDefend extends Ability implements IAbilityDefend {
/**
* Subclass-specific defend behavior. Called only for physical melee hits while defending.
*
- * @param amount The incoming damage
+ * @param attacker The entity that hit the caster
+ * @param amount The incoming damage
* @return The modified damage the caster should take
*/
- protected abstract float performDefend(float amount);
+ protected abstract float performDefend(EntityLivingBase attacker, float amount);
// ═══════════════════════════════════════════════════════════════════
// SUBCLASS HOOKS
// ═══════════════════════════════════════════════════════════════════
- protected void onDefendStart(EntityLivingBase caster) {}
-
- protected abstract void onDefendTick(EntityLivingBase caster, EntityLivingBase target, int tick);
-
/**
* Subclass-specific NBT persistence.
*/
@@ -142,6 +147,49 @@ public abstract class AbilityDefend extends Ability implements IAbilityDefend {
@SideOnly(Side.CLIENT)
protected abstract void getTypeDefinitions(List