diff --git a/src/api b/src/api index 3050910ef..2b21264ad 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit 3050910efbc6e301e4ef18fefc20529c507a7bae +Subproject commit 2b21264ada69ec5e800977a000e892bc82d7c61f 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 e5dc7e493..a82a8fc6e 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -55,7 +55,7 @@ public abstract class Ability implements IAbility { protected boolean interruptible = true; // Feedback - protected boolean lockMovement = true; + protected LockMovementType lockMovement = LockMovementType.WINDUP; protected int windUpColor = 0x80FF4400; // Telegraph color during wind up protected int activeColor = 0xC0FF0000; // Telegraph warning/active color @@ -662,7 +662,7 @@ public abstract class Ability implements IAbility { nbt.setInteger("windUp", windUpTicks); nbt.setInteger("recovery", dazedTicks); nbt.setBoolean("interruptible", interruptible); - nbt.setBoolean("lockMovement", lockMovement); + nbt.setInteger("lockMovement", lockMovement.ordinal()); nbt.setInteger("windUpColor", windUpColor); nbt.setInteger("activeColor", activeColor); nbt.setString("windUpSound", windUpSound); @@ -707,7 +707,7 @@ public abstract class Ability implements IAbility { windUpTicks = nbt.getInteger("windUp"); dazedTicks = nbt.getInteger("recovery"); interruptible = nbt.getBoolean("interruptible"); - lockMovement = nbt.getBoolean("lockMovement"); + lockMovement = LockMovementType.fromOrdinal(nbt.getInteger("lockMovement")); // Support old telegraphColor key for backwards compatibility if (nbt.hasKey("windUpColor")) { windUpColor = nbt.getInteger("windUpColor"); @@ -868,14 +868,62 @@ public abstract class Ability implements IAbility { this.interruptible = interruptible; } - public boolean isLockMovement() { + public LockMovementType getLockMovement() { return lockMovement; } - public void setLockMovement(boolean lockMovement) { + public void setLockMovement(LockMovementType lockMovement) { this.lockMovement = lockMovement; } + /** + * API method: Get lock movement type as integer. + * @return 0=NO, 1=WINDUP, 2=ACTIVE, 3=WINDUP_AND_ACTIVE + */ + @Override + public int getLockMovementType() { + return lockMovement.ordinal(); + } + + /** + * API method: Set lock movement type from integer. + * @param type 0=NO, 1=WINDUP, 2=ACTIVE, 3=WINDUP_AND_ACTIVE + */ + @Override + public void setLockMovementType(int type) { + this.lockMovement = LockMovementType.fromOrdinal(type); + } + + /** + * Check if movement should be locked during WINDUP phase. + */ + @Override + public boolean isMovementLockedDuringWindup() { + return lockMovement.locksWindup(); + } + + /** + * Check if movement should be locked during ACTIVE phase. + */ + @Override + public boolean isMovementLockedDuringActive() { + return lockMovement.locksActive(); + } + + /** + * Check if movement should be locked during the current phase. + */ + public boolean isMovementLockedForCurrentPhase() { + switch (phase) { + case WINDUP: + return lockMovement.locksWindup(); + case ACTIVE: + return lockMovement.locksActive(); + default: + return false; + } + } + public int getWindUpColor() { return windUpColor; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/LockMovementType.java b/src/main/java/kamkeel/npcs/controllers/data/ability/LockMovementType.java new file mode 100644 index 000000000..1b81a3bb3 --- /dev/null +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/LockMovementType.java @@ -0,0 +1,83 @@ +package kamkeel.npcs.controllers.data.ability; + +/** + * Defines when an ability locks NPC movement and rotation. + */ +public enum LockMovementType { + /** + * No movement lock - NPC can move freely during both phases. + */ + NO, + + /** + * Lock movement during WINDUP phase only. + * NPC can move during ACTIVE phase. + */ + WINDUP, + + /** + * Lock movement during ACTIVE phase only. + * NPC can move during WINDUP phase. + */ + ACTIVE, + + /** + * Lock movement during both WINDUP and ACTIVE phases. + */ + WINDUP_AND_ACTIVE; + + /** + * Check if movement should be locked during WINDUP phase. + */ + public boolean locksWindup() { + return this == WINDUP || this == WINDUP_AND_ACTIVE; + } + + /** + * Check if movement should be locked during ACTIVE phase. + */ + public boolean locksActive() { + return this == ACTIVE || this == WINDUP_AND_ACTIVE; + } + + /** + * Get display name for GUI. + */ + public String getDisplayKey() { + switch (this) { + case NO: + return "gui.no"; + case WINDUP: + return "ability.lockMove.windup"; + case ACTIVE: + return "ability.lockMove.active"; + case WINDUP_AND_ACTIVE: + return "ability.lockMove.both"; + default: + return "gui.no"; + } + } + + /** + * Get all display keys for GUI dropdown. + */ + public static String[] getDisplayKeys() { + return new String[]{ + "gui.no", + "ability.lockMove.windup", + "ability.lockMove.active", + "ability.lockMove.both" + }; + } + + /** + * Get LockMovementType from ordinal, with fallback to WINDUP. + */ + public static LockMovementType fromOrdinal(int ordinal) { + LockMovementType[] values = values(); + if (ordinal >= 0 && ordinal < values.length) { + return values[ordinal]; + } + return WINDUP; + } +} 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 d87ed05ee..1f6f31250 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; @@ -47,7 +48,7 @@ public class AbilityCharge extends Ability implements IAbilityCharge { this.targetingMode = TargetingMode.AGGRO_TARGET; this.maxRange = 20.0f; this.minRange = 4.0f; - this.lockMovement = false; // Movement IS the ability + this.lockMovement = LockMovementType.WINDUP; this.cooldownTicks = 0; this.windUpTicks = 20; // LINE telegraph showing charge path 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 1d77e9219..9db9d7700 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.EntityLivingBase; @@ -54,7 +55,7 @@ public class AbilityCutter extends Ability implements IAbilityCutter { this.name = "Cutter"; this.targetingMode = TargetingMode.AOE_SELF; this.maxRange = 8.0f; - this.lockMovement = true; + this.lockMovement = LockMovementType.NO; this.cooldownTicks = 0; this.windUpTicks = 20; this.telegraphType = TelegraphType.CONE; 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 677578745..2c03de4c2 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.EntityLivingBase; @@ -88,7 +89,7 @@ public class AbilityDash extends Ability implements IAbilityDash { this.targetingMode = TargetingMode.AGGRO_TARGET; this.maxRange = 20.0f; this.minRange = 0.0f; - this.lockMovement = false; + this.lockMovement = LockMovementType.NO; this.cooldownTicks = 0; this.windUpTicks = 5; // No telegraph for dash - it's a quick evasive move diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java index 2c7b8e43c..a68e38cd6 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java @@ -4,6 +4,7 @@ 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.AnchorPoint; +import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; @@ -83,6 +84,7 @@ public class AbilityDisc extends Ability implements IAbilityDisc { this.minRange = 5.0f; this.cooldownTicks = 0; this.windUpTicks = 20; + this.lockMovement = LockMovementType.WINDUP; this.telegraphType = TelegraphType.CIRCLE; this.showTelegraph = true; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java index 790489b2c..b8946306a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java @@ -5,6 +5,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; import kamkeel.npcs.controllers.data.ability.AbilityAnimation; import kamkeel.npcs.controllers.data.ability.AnchorPoint; +import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; @@ -85,6 +86,7 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { this.minRange = 5.0f; this.cooldownTicks = 0; this.windUpTicks = 40; + this.lockMovement = LockMovementType.WINDUP_AND_ACTIVE; this.telegraphType = TelegraphType.CIRCLE; this.showTelegraph = true; } @@ -145,7 +147,7 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { stunDuration, slowDuration, slowLevel, maxDistance, maxLifetime, lightningEffect, lightningDensity, lightningRadius, - lockMovement, // Anchored mode + lockMovement.locksActive(), // Anchored mode during firing windUpTicks, // Charge duration = windup duration offsetDist, // Offset distance (used by FRONT anchor) anchorPoint // Anchor point for charging position @@ -311,7 +313,7 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { public float getLightningRadius() { return lightningRadius; } public void setLightningRadius(float lightningRadius) { this.lightningRadius = lightningRadius; } - + @Override public Animation getWindUpAnimation() { if (windUpAnimationId == -1) 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 84701b79e..92c7ca58e 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.EntityLivingBase; @@ -50,7 +51,7 @@ public class AbilityGuard extends Ability implements IAbilityGuard { this.typeId = "ability.cnpc.guard"; this.name = "Guard"; this.targetingMode = TargetingMode.SELF; - this.lockMovement = true; + this.lockMovement = LockMovementType.ACTIVE; this.cooldownTicks = 0; this.windUpTicks = 10; this.interruptible = false; // Hard to interrupt while guarding 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 79e43e2cc..61841ded4 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; @@ -83,7 +84,7 @@ public class AbilityHazard extends Ability implements IAbilityHazard { this.name = "Hazard"; this.targetingMode = TargetingMode.AGGRO_TARGET; this.maxRange = 15.0f; - this.lockMovement = true; + this.lockMovement = LockMovementType.WINDUP; this.cooldownTicks = 0; this.windUpTicks = 30; this.telegraphType = TelegraphType.CIRCLE; 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 11aed6c47..406be2f3a 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.Entity; @@ -49,7 +50,7 @@ public class AbilityHeal extends Ability implements IAbilityHeal { this.typeId = "ability.cnpc.heal"; this.name = "Heal"; this.targetingMode = TargetingMode.SELF; - this.lockMovement = true; + this.lockMovement = LockMovementType.WINDUP; this.cooldownTicks = 0; this.windUpTicks = 30; // No telegraph for heal - it's a self/ally buff 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 82091c041..4ed4a0e78 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.EntityLivingBase; @@ -29,7 +30,7 @@ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { this.targetingMode = TargetingMode.AGGRO_TARGET; this.maxRange = 3.0f; this.minRange = 0.0f; - this.lockMovement = true; + this.lockMovement = LockMovementType.NO; this.cooldownTicks = 0; this.windUpTicks = 30; this.telegraphType = TelegraphType.POINT; diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java index 44b6bc0b5..da9f07780 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import kamkeel.npcs.entity.EntityAbilityLaser; @@ -63,6 +64,7 @@ public class AbilityLaserShot extends Ability implements IAbilityLaserShot { this.minRange = 3.0f; this.cooldownTicks = 0; this.windUpTicks = 15; + this.lockMovement = LockMovementType.WINDUP; this.telegraphType = TelegraphType.LINE; this.showTelegraph = true; } 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 fabdf6ab0..336f54e7c 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 @@ -5,6 +5,7 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.Ability; import kamkeel.npcs.controllers.data.ability.AbilityAnimation; import kamkeel.npcs.controllers.data.ability.AnchorPoint; +import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; @@ -84,6 +85,7 @@ public class AbilityOrb extends Ability implements IAbilityOrb { this.minRange = 5.0f; this.cooldownTicks = 0; this.windUpTicks = 30; + this.lockMovement = LockMovementType.WINDUP; this.telegraphType = TelegraphType.CIRCLE; this.showTelegraph = true; } 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 56b12028e..6b81fabe7 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.Entity; @@ -42,6 +43,7 @@ public class AbilityProjectile extends Ability implements IAbilityProjectile { this.maxRange = 20.0f; this.cooldownTicks = 0; this.windUpTicks = 15; + this.lockMovement = LockMovementType.NO; // No telegraph for projectile - it's a ranged attack this.telegraphType = TelegraphType.NONE; this.showTelegraph = false; 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 c6b93134a..006084f5e 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.EntityLivingBase; @@ -35,7 +36,7 @@ public class AbilityShockwave extends Ability implements IAbilityShockwave { this.name = "Shockwave"; this.targetingMode = TargetingMode.AOE_SELF; this.maxRange = 15.0f; - this.lockMovement = true; + this.lockMovement = LockMovementType.WINDUP_AND_ACTIVE; this.cooldownTicks = 0; this.windUpTicks = 25; this.telegraphType = TelegraphType.CIRCLE; 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 ba49ffb2c..b9da81dc5 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; @@ -52,7 +53,7 @@ public class AbilitySlam extends Ability implements IAbilitySlam { this.targetingMode = TargetingMode.AOE_SELF; // Can also be AOE_TARGET to leap to target this.windUpTicks = 30; this.cooldownTicks = 0; - this.lockMovement = true; + this.lockMovement = LockMovementType.WINDUP; this.minRange = 2.0f; this.maxRange = 15.0f; this.telegraphType = TelegraphType.CIRCLE; diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java index 66f589a00..2abbbbb48 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; @@ -54,7 +55,7 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper { this.targetingMode = TargetingMode.AGGRO_TARGET; this.maxRange = 15.0f; this.minRange = 0.0f; - this.lockMovement = true; + this.lockMovement = LockMovementType.WINDUP_AND_ACTIVE; this.cooldownTicks = 0; this.windUpTicks = 60; // Circle telegraph to show range 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 05293a467..1fef00a55 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.block.Block; @@ -63,6 +64,7 @@ public class AbilityTeleport extends Ability implements IAbilityTeleport { this.minRange = 5.0f; this.cooldownTicks = 0; this.windUpTicks = 10; + this.lockMovement = LockMovementType.NO; // No telegraph for teleport - it's instant repositioning this.telegraphType = TelegraphType.NONE; this.showTelegraph = false; 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 b14a9ad67..6bf69a60b 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; @@ -66,7 +67,7 @@ public class AbilityTrap extends Ability implements IAbilityTrap { this.name = "Trap"; this.targetingMode = TargetingMode.AGGRO_TARGET; this.maxRange = 15.0f; - this.lockMovement = true; + this.lockMovement = LockMovementType.WINDUP; this.cooldownTicks = 0; this.windUpTicks = 20; this.telegraphType = TelegraphType.CIRCLE; 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 a85bbc442..1bcfb7cbc 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 @@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type; 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.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.EntityLivingBase; @@ -53,7 +54,7 @@ public class AbilityVortex extends Ability implements IAbilityVortex { this.name = "Vortex"; this.targetingMode = TargetingMode.AOE_SELF; this.maxRange = 15.0f; - this.lockMovement = true; + this.lockMovement = LockMovementType.WINDUP_AND_ACTIVE; this.cooldownTicks = 0; this.windUpTicks = 30; this.telegraphType = TelegraphType.CIRCLE; diff --git a/src/main/java/noppes/npcs/DataAbilities.java b/src/main/java/noppes/npcs/DataAbilities.java index 2ddabc588..538829cef 100644 --- a/src/main/java/noppes/npcs/DataAbilities.java +++ b/src/main/java/noppes/npcs/DataAbilities.java @@ -79,7 +79,7 @@ public class DataAbilities { private transient List recentHitTimes = new ArrayList<>(); /** - * Locked rotation values for ACTIVE phase with lockMovement. + * Locked rotation values for ACTIVE phase when movement is locked. * Stored when entering ACTIVE phase, applied every tick to prevent rotation changes. */ private transient boolean rotationLocked = false; @@ -146,9 +146,9 @@ public class DataAbilities { // Remove telegraph - it has served its purpose removeTelegraph(currentAbility); - // Lock rotation if lockMovement is true + // Lock rotation if movement is locked during ACTIVE phase // Capture current rotation values to force them every tick - if (currentAbility.isLockMovement()) { + if (currentAbility.isMovementLockedDuringActive()) { captureLockedRotation(); } @@ -191,6 +191,32 @@ public class DataAbilities { handleAbilityCompletion(target); break; } + + // Apply movement control if ability is still executing + if (currentAbility != null && currentAbility.isExecuting()) { + applyMovementControl(); + } + } + + /** + * Apply movement control based on lock movement settings. + * Called every tick during ability execution. + */ + private void applyMovementControl() { + if (currentAbility == null) return; + + // Check if movement should be locked for the current phase + if (currentAbility.isMovementLockedForCurrentPhase()) { + // Clear navigator to prevent AI pathfinding + npc.getNavigator().clearPathEntity(); + + // Zero motion if ability doesn't have its own movement + // This allows abilities like Charge/Slam to control their own motion + if (!currentAbility.hasAbilityMovement()) { + npc.motionX = 0; + npc.motionZ = 0; + } + } } /** @@ -210,29 +236,11 @@ public class DataAbilities { npc.wrappedNPC, currentAbility, target); NpcAPI.EVENT_BUS.post(completeEvent); - // Clean up and roll cooldown + // Release rotation lock before cleanup + releaseLockedRotation(); + + // Clean up and roll cooldown (this sets currentAbility to null) onAbilityComplete(); - - // Clear AI pathfinding if ability is controlling movement - // But DON'T zero motion - let the ability set it if needed - if (currentAbility != null && currentAbility.isExecuting()) { - if (isAbilityControllingMovement()) { - // Clear navigator so AI doesn't fight with ability movement - npc.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; - } - } - - // Unlock rotation when leaving ACTIVE phase - if (rotationLocked && currentAbility.getPhase() != AbilityPhase.ACTIVE) { - releaseLockedRotation(); - } - } } /** @@ -787,8 +795,8 @@ public class DataAbilities { * Called by AI tasks to determine if they should try to path. *

* Rules: - * - WINDUP phase: Block AI if lockMovement is true - * - ACTIVE phase: Block AI if lockMovement OR hasAbilityMovement is true + * - WINDUP phase: Block AI if movement is locked during windup + * - ACTIVE phase: Block AI if movement is locked during active OR hasAbilityMovement is true * - DAZED phase: Always block AI (NPC is stunned) */ public boolean isAbilityControllingMovement() { @@ -800,15 +808,15 @@ public class DataAbilities { switch (phase) { case WINDUP: - // During windup, only block if lockMovement is set - // This allows NPC to keep chasing while winding up if lockMovement=false - return currentAbility.isLockMovement(); + // During windup, only block if movement is locked during windup + // This allows NPC to keep chasing while winding up if not locked + return currentAbility.isMovementLockedDuringWindup(); case ACTIVE: // During active phase, block if either: - // - lockMovement is true (stationary ability) + // - movement is locked during active (stationary ability) // - hasAbilityMovement is true (ability is moving the NPC itself) - return currentAbility.isLockMovement() || currentAbility.hasAbilityMovement(); + return currentAbility.isMovementLockedDuringActive() || currentAbility.hasAbilityMovement(); case DAZED: // During dazed phase, always block - NPC is stunned from interrupt @@ -821,7 +829,7 @@ public class DataAbilities { /** * Check if NPC's look direction should be locked to target. - * Only locks during ACTIVE phase when lockMovement is true. + * Only locks during ACTIVE phase when movement is locked during active. * This allows the NPC to freely track target during WINDUP and DAZED. */ public boolean shouldLockLookDirection() { @@ -834,7 +842,7 @@ public class DataAbilities { return false; } - return currentAbility.isLockMovement(); + return currentAbility.isMovementLockedDuringActive(); } /** @@ -854,7 +862,7 @@ public class DataAbilities { /** * Capture current rotation values to lock NPC's look direction. - * Called when entering ACTIVE phase with lockMovement enabled. + * Called when entering ACTIVE phase with movement locked during active. */ private void captureLockedRotation() { lockedYaw = npc.rotationYaw; diff --git a/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java b/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java index 831420473..11dbcbc85 100644 --- a/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java +++ b/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java @@ -2,6 +2,7 @@ package noppes.npcs.client.gui.advanced; import kamkeel.npcs.controllers.data.ability.Ability; import kamkeel.npcs.controllers.data.ability.Condition; +import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import noppes.npcs.controllers.data.Animation; @@ -58,7 +59,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi protected String name; protected boolean enabled; protected int weight; - protected boolean lockMovement; + protected LockMovementType lockMovement; protected boolean interruptible; // Timing @@ -111,7 +112,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi this.name = ability.getName() != null ? ability.getName() : ""; this.enabled = ability.isEnabled(); this.weight = ability.getWeight(); - this.lockMovement = ability.isLockMovement(); + this.lockMovement = ability.getLockMovement(); this.interruptible = ability.isInterruptible(); // Timing @@ -251,7 +252,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi addTextField(weightField); addLabel(new GuiNpcLabel(5, "ability.lockMove", col2LabelX, y + 5)); - GuiNpcButton lockMoveBtn = new GuiNpcButton(16, col2FieldX, y, 40, 20, new String[]{"gui.no", "gui.yes"}, lockMovement ? 1 : 0); + GuiNpcButton lockMoveBtn = new GuiNpcButton(16, col2FieldX, y, 60, 20, LockMovementType.getDisplayKeys(), lockMovement.ordinal()); lockMoveBtn.setHoverText("ability.hover.lockMove"); addButton(lockMoveBtn); @@ -644,7 +645,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi interruptible = ((GuiNpcButton) guibutton).getValue() == 1; initGui(); // Refresh to show/hide dazed ticks field } else if (id == 16) { - lockMovement = ((GuiNpcButton) guibutton).getValue() == 1; + lockMovement = LockMovementType.fromOrdinal(((GuiNpcButton) guibutton).getValue()); } else if (id == 17) { // Sync windup ticks with animation duration syncWindupWithAnimation(); @@ -920,7 +921,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi this.name = ability.getName() != null ? ability.getName() : ""; this.enabled = ability.isEnabled(); this.weight = ability.getWeight(); - this.lockMovement = ability.isLockMovement(); + this.lockMovement = ability.getLockMovement(); this.interruptible = ability.isInterruptible(); this.cooldownTicks = ability.getCooldownTicks(); diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang index d4f75d883..fd148ea08 100644 --- a/src/main/resources/assets/customnpcs/lang/en_US.lang +++ b/src/main/resources/assets/customnpcs/lang/en_US.lang @@ -1519,6 +1519,9 @@ ability.dazed=Dazed Ticks ability.interruptible=Interruptible ability.threshold=Threshold ability.lockMove=Lock Move +ability.lockMove.windup=Windup +ability.lockMove.active=Active +ability.lockMove.both=Both ability.telegraph=Telegraph ability.telegraphType=Telegraph Type