diff --git a/src/api b/src/api index 3f8ccc087..f383fc303 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit 3f8ccc087f781a43c2e5a2044f5d859be53d88c8 +Subproject commit f383fc3037221791e2f22a272580df9be013810f 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 3d49c689e..5a13cf917 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -67,6 +67,7 @@ public abstract class Ability implements IAbility { // Feedback protected LockMovementType lockMovement = LockMovementType.WINDUP; + protected LockType lockType = LockType.BOTH; protected int windUpColor = 0x80FF4400; // Telegraph color during wind up protected int activeColor = 0xC0FF0000; // Telegraph warning/active color @@ -390,15 +391,27 @@ public abstract class Ability implements IAbility { defs.add(FieldDef.intField("ability.cooldownTicks", this::getCooldownTicks, this::setCooldownTicks) .tab("General").range(0, 10000)); defs.add(FieldDef.section("ability.section.movement").tab("General")); - defs.add(FieldDef.stringEnumField("ability.lockMovement", LockMovementType.getDisplayKeys(), - () -> this.getLockMovement().getDisplayKey(), - v -> { - String[] keys = LockMovementType.getDisplayKeys(); - for (int i = 0; i < keys.length; i++) { - if (keys[i].equals(v)) { this.setLockMovement(LockMovementType.fromOrdinal(i)); break; } - } - }) - .tab("General").hover("ability.hover.lockMove")); + defs.add(FieldDef.row( + FieldDef.stringEnumField("ability.lockPosition", LockMovementType.getDisplayKeys(), + () -> this.getLockMovement().getDisplayKey(), + v -> { + String[] keys = LockMovementType.getDisplayKeys(); + for (int i = 0; i < keys.length; i++) { + if (keys[i].equals(v)) { this.setLockMovement(LockMovementType.fromOrdinal(i)); break; } + } + }) + .hover("ability.hover.lockPosition"), + FieldDef.stringEnumField("ability.lockType", LockType.getDisplayKeys(), + () -> this.getLockType().getDisplayKey(), + v -> { + String[] keys = LockType.getDisplayKeys(); + for (int i = 0; i < keys.length; i++) { + if (keys[i].equals(v)) { this.setLockType(LockType.fromOrdinal(i)); break; } + } + }) + .hover("ability.hover.lockType") + .visibleWhen(() -> this.lockMovement != LockMovementType.NO) + ).tab("General")); defs.add(FieldDef.row( FieldDef.boolField("ability.interruptible", this::isInterruptible, this::setInterruptible) .hover("ability.hover.interruptible"), @@ -940,6 +953,7 @@ public abstract class Ability implements IAbility { nbt.setInteger("recovery", dazedTicks); nbt.setBoolean("interruptible", interruptible); nbt.setInteger("lockMovement", lockMovement.ordinal()); + nbt.setInteger("lockType", lockType.ordinal()); nbt.setInteger("windUpColor", windUpColor); nbt.setInteger("activeColor", activeColor); nbt.setString("windUpSound", windUpSound); @@ -990,6 +1004,7 @@ public abstract class Ability implements IAbility { dazedTicks = nbt.getInteger("recovery"); interruptible = nbt.getBoolean("interruptible"); lockMovement = LockMovementType.fromOrdinal(nbt.getInteger("lockMovement")); + lockType = nbt.hasKey("lockType") ? LockType.fromOrdinal(nbt.getInteger("lockType")) : LockType.BOTH; windUpColor = nbt.getInteger("windUpColor"); activeColor = nbt.getInteger("activeColor"); windUpSound = nbt.getString("windUpSound"); @@ -1154,6 +1169,14 @@ public abstract class Ability implements IAbility { this.lockMovement = lockMovement; } + public LockType getLockType() { + return lockType; + } + + public void setLockType(LockType lockType) { + this.lockType = lockType; + } + /** * API method: Get lock movement type as integer. * @return 0=NO, 1=WINDUP, 2=ACTIVE, 3=WINDUP_AND_ACTIVE @@ -1173,19 +1196,53 @@ public abstract class Ability implements IAbility { } /** - * Check if movement should be locked during WINDUP phase. + * API method: Get lock type as integer. + * @return 0=MOVEMENT, 1=ROTATION, 2=BOTH */ @Override - public boolean isMovementLockedDuringWindup() { - return lockMovement.locksWindup(); + public int getLockTypeOrdinal() { + return lockType.ordinal(); } /** - * Check if movement should be locked during ACTIVE phase. + * API method: Set lock type from integer. + * @param type 0=MOVEMENT, 1=ROTATION, 2=BOTH + */ + @Override + public void setLockTypeOrdinal(int type) { + this.lockType = LockType.fromOrdinal(type); + } + + /** + * Check if movement (pathfinding/motion) should be locked during WINDUP phase. + */ + @Override + public boolean isMovementLockedDuringWindup() { + return lockMovement.locksWindup() && lockType.locksMovement(); + } + + /** + * Check if movement (pathfinding/motion) should be locked during ACTIVE phase. */ @Override public boolean isMovementLockedDuringActive() { - return lockMovement.locksActive(); + return lockMovement.locksActive() && lockType.locksMovement(); + } + + /** + * Check if rotation (yaw/pitch) should be locked during WINDUP phase. + */ + @Override + public boolean isRotationLockedDuringWindup() { + return lockMovement.locksWindup() && lockType.locksRotation(); + } + + /** + * Check if rotation (yaw/pitch) should be locked during ACTIVE phase. + */ + @Override + public boolean isRotationLockedDuringActive() { + return lockMovement.locksActive() && lockType.locksRotation(); } /** @@ -1194,9 +1251,23 @@ public abstract class Ability implements IAbility { public boolean isMovementLockedForCurrentPhase() { switch (phase) { case WINDUP: - return lockMovement.locksWindup(); + return isMovementLockedDuringWindup(); case ACTIVE: - return lockMovement.locksActive(); + return isMovementLockedDuringActive(); + default: + return false; + } + } + + /** + * Check if rotation should be locked during the current phase. + */ + public boolean isRotationLockedForCurrentPhase() { + switch (phase) { + case WINDUP: + return isRotationLockedDuringWindup(); + case ACTIVE: + return isRotationLockedDuringActive(); default: return false; } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/LockType.java b/src/main/java/kamkeel/npcs/controllers/data/ability/LockType.java new file mode 100644 index 000000000..904a6c876 --- /dev/null +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/LockType.java @@ -0,0 +1,47 @@ +package kamkeel.npcs.controllers.data.ability; + +/** + * Defines what an ability locks when Lock Position is enabled. + */ +public enum LockType { + MOVEMENT, + ROTATION, + BOTH; + + public boolean locksMovement() { + return this == MOVEMENT || this == BOTH; + } + + public boolean locksRotation() { + return this == ROTATION || this == BOTH; + } + + public String getDisplayKey() { + switch (this) { + case MOVEMENT: + return "ability.lockType.movement"; + case ROTATION: + return "ability.lockType.rotation"; + case BOTH: + return "ability.lockType.both"; + default: + return "ability.lockType.both"; + } + } + + public static String[] getDisplayKeys() { + return new String[]{ + "ability.lockType.movement", + "ability.lockType.rotation", + "ability.lockType.both" + }; + } + + public static LockType fromOrdinal(int ordinal) { + LockType[] values = values(); + if (ordinal >= 0 && ordinal < values.length) { + return values[ordinal]; + } + return BOTH; + } +} diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java index 495d0bdef..c8889dfe9 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java @@ -126,6 +126,11 @@ public class AbilityBeam extends Ability implements IAbilityEnergyBeam { public void onComplete(EntityLivingBase caster, EntityLivingBase target) { } + @Override + public void onInterrupt(EntityLivingBase caster, net.minecraft.util.DamageSource source, float damage) { + cleanup(); + } + @Override public void cleanup() { // Despawn beam entity if still alive diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java index f7046d322..56c24e791 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java @@ -167,6 +167,11 @@ public class AbilityBeamDual extends Ability { public void onComplete(EntityLivingBase caster, EntityLivingBase target) { } + @Override + public void onInterrupt(EntityLivingBase caster, net.minecraft.util.DamageSource source, float damage) { + cleanup(); + } + @Override public void cleanup() { // Despawn beam entity if still alive 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 f70e44ccb..0bbad4209 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 @@ -127,6 +127,11 @@ public class AbilityDisc extends Ability implements IAbilityDisc { public void onComplete(EntityLivingBase caster, EntityLivingBase target) { } + @Override + public void onInterrupt(EntityLivingBase caster, net.minecraft.util.DamageSource source, float damage) { + cleanup(); + } + @Override public void cleanup() { // Despawn disc entity if still alive diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java index 98e924b8a..0dea0a072 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java @@ -176,6 +176,11 @@ public class AbilityDiscDual extends Ability { public void onComplete(EntityLivingBase caster, EntityLivingBase target) { } + @Override + public void onInterrupt(EntityLivingBase caster, net.minecraft.util.DamageSource source, float damage) { + cleanup(); + } + @Override public void cleanup() { // Despawn disc entity if still alive 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 3fb4335be..48fddd63c 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 @@ -136,6 +136,7 @@ public class AbilityLaserShot extends Ability implements IAbilityLaserShot { @Override public void onInterrupt(EntityLivingBase caster, DamageSource source, float damage) { + cleanup(); } @Override 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 e3ae6c228..519fef749 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 @@ -122,6 +122,11 @@ public class AbilityOrb extends Ability implements IAbilityOrb { // Nothing to clean up - entity manages itself } + @Override + public void onInterrupt(EntityLivingBase caster, net.minecraft.util.DamageSource source, float damage) { + cleanup(); + } + @Override public void cleanup() { // Despawn orb entity if still alive diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java index e158062d2..be323014b 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java @@ -211,6 +211,11 @@ public class AbilityOrbBarrage extends Ability { return true; } + @Override + public void onInterrupt(EntityLivingBase caster, DamageSource source, float damage) { + cleanup(); + } + @Override public void cleanup() { currentOrb = 0; diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java index 390610a2e..3fdd5eda6 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java @@ -161,7 +161,11 @@ public class AbilityOrbDual extends Ability { @Override public void onComplete(EntityLivingBase caster, EntityLivingBase target) { - // Nothing to clean up - entity manages itself + } + + @Override + public void onInterrupt(EntityLivingBase caster, net.minecraft.util.DamageSource source, float damage) { + cleanup(); } @Override 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 30b57bf6d..1be741d35 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 @@ -217,9 +217,6 @@ public class AbilitySlam extends Ability implements IAbilitySlam { double dragPowN = Math.pow(drag, flightTicks); double vHorizontal = horizontalDist * (1.0 - drag) / (1.0 - dragPowN); - // Speed scales horizontal velocity to cover ground faster - vHorizontal *= speedFactor; - // Adjust vertical velocity for height difference between start and target if (dy > 0) { vy += dy / flightTicks * 1.5; // Going up - need more velocity @@ -438,7 +435,7 @@ public class AbilitySlam extends Ability implements IAbilitySlam { int flightTicks = (int) Math.max(10, Math.min(horizontalDist * 1.5 / speedFactor, 40)); double drag = 0.91; double dragPowN = Math.pow(drag, flightTicks); - double vHorizontal = horizontalDist * (1.0 - drag) / (1.0 - dragPowN) * speedFactor; + double vHorizontal = horizontalDist * (1.0 - drag) / (1.0 - dragPowN); double dirX = dx / horizontalDist; double dirZ = dz / horizontalDist; 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 1aa6fa139..2fcc62956 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 @@ -100,6 +100,11 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper { } } + @Override + public void onInterrupt(EntityLivingBase caster, net.minecraft.util.DamageSource source, float damage) { + cleanup(); + } + @Override public void cleanup() { // Clean up entity if still alive diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java index f8053509b..1a036573e 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java @@ -205,10 +205,19 @@ public class EntityAbilityLaser extends EntityAbilityProjectile { startY = posY; startZ = posZ; - // Calculate velocity toward target + // Always derive direction from the owner's current yaw/pitch. + // This ensures the laser fires in the direction the NPC is visually facing, + // which matches the telegraph line direction regardless of Lock Movement mode. Entity owner = getOwnerEntity(); - if (target != null) { + if (owner != null) { + float yaw = (float) Math.toRadians(owner.rotationYaw); + float pitch = (float) Math.toRadians(owner.rotationPitch); + this.dirX = -Math.sin(yaw) * Math.cos(pitch); + this.dirY = -Math.sin(pitch); + this.dirZ = Math.cos(yaw) * Math.cos(pitch); + } else if (target != null) { + // Fallback: aim at target if owner is somehow unavailable double dx = target.posX - startX; double dy = (target.posY + target.getEyeHeight() - 0.4) - startY; double dz = target.posZ - startZ; @@ -218,13 +227,6 @@ public class EntityAbilityLaser extends EntityAbilityProjectile { this.dirY = dy / len; this.dirZ = dz / len; } - } else if (owner != null) { - // Fire in NPC's facing direction - float yaw = (float) Math.toRadians(owner.rotationYaw); - float pitch = (float) Math.toRadians(owner.rotationPitch); - this.dirX = -Math.sin(yaw) * Math.cos(pitch); - this.dirY = -Math.sin(pitch); - this.dirZ = Math.cos(yaw) * Math.cos(pitch);; } setPosition(endX, endY, endZ); diff --git a/src/main/java/noppes/npcs/DataAbilities.java b/src/main/java/noppes/npcs/DataAbilities.java index 1d91dad97..3f8cb5357 100644 --- a/src/main/java/noppes/npcs/DataAbilities.java +++ b/src/main/java/noppes/npcs/DataAbilities.java @@ -18,6 +18,7 @@ import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.scripted.NpcAPI; import noppes.npcs.scripted.event.AbilityEvent; + import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -147,10 +148,15 @@ public class DataAbilities { // Remove telegraph - it has served its purpose removeTelegraph(currentAbility); - // Lock rotation if movement is locked during ACTIVE phase - // Capture current rotation values to force them every tick - if (currentAbility.isMovementLockedDuringActive()) { - captureLockedRotation(); + // Handle rotation lock transition from WINDUP to ACTIVE + if (currentAbility.isRotationLockedDuringActive()) { + // ACTIVE or WINDUP_AND_ACTIVE: capture (or keep) rotation lock + if (!rotationLocked) { + captureLockedRotation(); + } + } else if (rotationLocked) { + // WINDUP only: release the lock now that windup is over + releaseLockedRotation(); } // Play active sound and animation @@ -390,6 +396,9 @@ public class DataAbilities { executeImmediate(ability, target); } else { // Normal windup flow + if (ability.isRotationLockedDuringWindup()) { + captureLockedRotation(); + } spawnTelegraph(ability, target); playAbilitySound(ability.getWindUpSound()); playAbilityAnimation(ability.getWindUpAnimation()); @@ -403,8 +412,8 @@ public class DataAbilities { * Called when windUpTicks is 0. */ private void executeImmediate(Ability ability, EntityLivingBase target) { - // Lock rotation if movement is locked during ACTIVE phase - if (ability.isMovementLockedDuringActive()) { + // Lock rotation if rotation is locked during ACTIVE phase + if (ability.isRotationLockedDuringActive()) { captureLockedRotation(); } @@ -934,9 +943,12 @@ public class DataAbilities { // ROTATION LOCKING // ═══════════════════════════════════════════════════════════════════ + /** Bit flag for rotation lock in the existing data watcher slot 15 bitfield */ + private static final int ROTATION_LOCKED_FLAG = 16; + /** * Capture current rotation values to lock NPC's look direction. - * Called when entering ACTIVE phase with movement locked during active. + * Called when entering a locked phase (WINDUP or ACTIVE depending on LockMovementType). */ private void captureLockedRotation() { lockedYaw = npc.rotationYaw; @@ -944,22 +956,53 @@ public class DataAbilities { lockedRenderYawOffset = npc.renderYawOffset; lockedPitch = npc.rotationPitch; rotationLocked = true; + npc.setBoolFlag(true, ROTATION_LOCKED_FLAG); } /** * Release the rotation lock. - * Called when leaving ACTIVE phase or ability completes. + * Called when leaving the locked phase or ability completes. */ private void releaseLockedRotation() { rotationLocked = false; + npc.setBoolFlag(false, ROTATION_LOCKED_FLAG); } /** * Apply locked rotation values to the NPC. * Called AFTER super.onLivingUpdate() in EntityNPCInterface to override - * any rotation changes made by the look helper or AI tasks. + * any rotation changes made by the look helper, AI tasks, or body smoothing. + * Runs on both client and server. */ public void applyLockedRotation() { + if (npc.worldObj.isRemote) { + // Client-side: check bit 16 in the existing flags data watcher (slot 15) + boolean flagActive = npc.getBoolFlag(ROTATION_LOCKED_FLAG); + if (!flagActive) { + rotationLocked = false; + return; + } + // First tick the flag is active: capture current rotation values + if (!rotationLocked) { + lockedYaw = npc.rotationYaw; + lockedYawHead = npc.rotationYawHead; + lockedRenderYawOffset = npc.renderYawOffset; + lockedPitch = npc.rotationPitch; + rotationLocked = true; + } + // Force all rotation values back to locked state + npc.rotationYaw = lockedYaw; + npc.rotationYawHead = lockedYawHead; + npc.renderYawOffset = lockedRenderYawOffset; + npc.rotationPitch = lockedPitch; + npc.prevRotationYaw = lockedYaw; + npc.prevRotationYawHead = lockedYawHead; + npc.prevRenderYawOffset = lockedRenderYawOffset; + npc.prevRotationPitch = lockedPitch; + return; + } + + // Server-side: use stored locked values if (!rotationLocked) { return; } diff --git a/src/main/java/noppes/npcs/ai/EntityAIAmbushTarget.java b/src/main/java/noppes/npcs/ai/EntityAIAmbushTarget.java index 4ee229b0e..3ba29ecd1 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIAmbushTarget.java +++ b/src/main/java/noppes/npcs/ai/EntityAIAmbushTarget.java @@ -93,7 +93,9 @@ public class EntityAIAmbushTarget extends EntityAIBase { * Updates the task */ public void updateTask() { - this.theEntity.getLookHelper().setLookPositionWithEntity(targetEntity, 30.0F, 30.0F); + if (!this.theEntity.abilities.isRotationLocked()) { + this.theEntity.getLookHelper().setLookPositionWithEntity(targetEntity, 30.0F, 30.0F); + } } private Vec3 findHidingSpot() { diff --git a/src/main/java/noppes/npcs/ai/EntityAIAttackTarget.java b/src/main/java/noppes/npcs/ai/EntityAIAttackTarget.java index 5fe559fc2..473c0bfb8 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIAttackTarget.java +++ b/src/main/java/noppes/npcs/ai/EntityAIAttackTarget.java @@ -118,7 +118,9 @@ public class EntityAIAttackTarget extends EntityAIBase { * Updates the task */ public void updateTask() { - this.npc.getLookHelper().setLookPositionWithEntity(this.entityTarget, 30.0F, 30.0F); + if (!this.npc.abilities.isRotationLocked()) { + this.npc.getLookHelper().setLookPositionWithEntity(this.entityTarget, 30.0F, 30.0F); + } // Skip pathfinding updates if ability is controlling movement if (!navOverride && !this.npc.abilities.isAbilityControllingMovement() && --this.field_75445_i <= 0) { diff --git a/src/main/java/noppes/npcs/ai/EntityAIDodgeShoot.java b/src/main/java/noppes/npcs/ai/EntityAIDodgeShoot.java index ef7b3f5ac..b07b911f4 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIDodgeShoot.java +++ b/src/main/java/noppes/npcs/ai/EntityAIDodgeShoot.java @@ -63,7 +63,7 @@ public class EntityAIDodgeShoot extends EntityAIBase { * Updates the task */ public void updateTask() { - if (this.entity.getAttackTarget() != null) + if (this.entity.getAttackTarget() != null && !this.entity.abilities.isRotationLocked()) this.entity.getLookHelper().setLookPositionWithEntity(this.entity.getAttackTarget(), 30.0F, 30.0F); } } diff --git a/src/main/java/noppes/npcs/ai/EntityAIFollow.java b/src/main/java/noppes/npcs/ai/EntityAIFollow.java index 61cabd38f..f236c0727 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIFollow.java +++ b/src/main/java/noppes/npcs/ai/EntityAIFollow.java @@ -55,7 +55,9 @@ public class EntityAIFollow extends EntityAIBase { if (updateTick < 10) return; updateTick = 0; - this.npc.getLookHelper().setLookPositionWithEntity(owner, 10.0F, (float) this.npc.getVerticalFaceSpeed()); + if (!this.npc.abilities.isRotationLocked()) { + this.npc.getLookHelper().setLookPositionWithEntity(owner, 10.0F, (float) this.npc.getVerticalFaceSpeed()); + } double speed = 1 + distance / 150; if (speed > 3) diff --git a/src/main/java/noppes/npcs/ai/EntityAILook.java b/src/main/java/noppes/npcs/ai/EntityAILook.java index 3448fc4ed..b9474a60c 100644 --- a/src/main/java/noppes/npcs/ai/EntityAILook.java +++ b/src/main/java/noppes/npcs/ai/EntityAILook.java @@ -26,7 +26,7 @@ public class EntityAILook extends EntityAIBase { */ @Override public boolean shouldExecute() { - return !npc.isAttacking() && npc.getNavigator().noPath() && !npc.isPlayerSleeping() && npc.isEntityAlive(); + return !npc.abilities.isRotationLocked() && !npc.isAttacking() && npc.getNavigator().noPath() && !npc.isPlayerSleeping() && npc.isEntityAlive(); } /** diff --git a/src/main/java/noppes/npcs/ai/EntityAIOrbitTarget.java b/src/main/java/noppes/npcs/ai/EntityAIOrbitTarget.java index 4c72ec278..0a9532261 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIOrbitTarget.java +++ b/src/main/java/noppes/npcs/ai/EntityAIOrbitTarget.java @@ -91,7 +91,9 @@ public class EntityAIOrbitTarget extends EntityAIBase { * Updates the task */ public void updateTask() { - this.theEntity.getLookHelper().setLookPositionWithEntity(targetEntity, 30.0F, 30.0F); + if (!this.theEntity.abilities.isRotationLocked()) { + this.theEntity.getLookHelper().setLookPositionWithEntity(targetEntity, 30.0F, 30.0F); + } if (this.theEntity.getNavigator().noPath() && this.tick >= 0) { if (this.theEntity.onGround && !this.theEntity.isInWater()) { double d0 = this.targetDistance * (double) (MathHelper.cos(angle / 180.0F * (float) Math.PI)); diff --git a/src/main/java/noppes/npcs/ai/EntityAIRangedAttack.java b/src/main/java/noppes/npcs/ai/EntityAIRangedAttack.java index af88ac905..5e8fa6ec0 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIRangedAttack.java +++ b/src/main/java/noppes/npcs/ai/EntityAIRangedAttack.java @@ -100,7 +100,9 @@ public class EntityAIRangedAttack extends EntityAIBase { * Updates the task */ public void updateTask() { - this.entityHost.getLookHelper().setLookPositionWithEntity(this.attackTarget, 30.0F, 30.0F); + if (!this.entityHost.abilities.isRotationLocked()) { + this.entityHost.getLookHelper().setLookPositionWithEntity(this.attackTarget, 30.0F, 30.0F); + } double var1 = this.entityHost.getDistanceSq(this.attackTarget.posX, this.attackTarget.boundingBox.minY, this.attackTarget.posZ); float field_82642_h = this.entityHost.stats.rangedRange * this.entityHost.stats.rangedRange; diff --git a/src/main/java/noppes/npcs/ai/EntityAIStalkTarget.java b/src/main/java/noppes/npcs/ai/EntityAIStalkTarget.java index 1b64a12b7..8adad1ee2 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIStalkTarget.java +++ b/src/main/java/noppes/npcs/ai/EntityAIStalkTarget.java @@ -68,7 +68,9 @@ public class EntityAIStalkTarget extends EntityAIBase { * Updates the task */ public void updateTask() { - this.theEntity.getLookHelper().setLookPositionWithEntity(targetEntity, 30.0F, 30.0F); + if (!this.theEntity.abilities.isRotationLocked()) { + this.theEntity.getLookHelper().setLookPositionWithEntity(targetEntity, 30.0F, 30.0F); + } if (this.theEntity.getNavigator().noPath() || this.overRide) { if (this.isLookingAway()) { diff --git a/src/main/java/noppes/npcs/ai/EntityAIWatchClosest.java b/src/main/java/noppes/npcs/ai/EntityAIWatchClosest.java index d30ae3183..159c38fc9 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIWatchClosest.java +++ b/src/main/java/noppes/npcs/ai/EntityAIWatchClosest.java @@ -31,7 +31,7 @@ public class EntityAIWatchClosest extends EntityAIBase { */ @Override public boolean shouldExecute() { - if (this.theWatcher.getRNG().nextFloat() >= this.field_75331_e || theWatcher.isInteracting()) { + if (this.theWatcher.abilities.isRotationLocked() || this.theWatcher.getRNG().nextFloat() >= this.field_75331_e || theWatcher.isInteracting()) { return false; } else { if (this.theWatcher.getAttackTarget() != null) { diff --git a/src/main/java/noppes/npcs/ai/EntityAIZigZagTarget.java b/src/main/java/noppes/npcs/ai/EntityAIZigZagTarget.java index 3e91cc84b..e99d31ca2 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIZigZagTarget.java +++ b/src/main/java/noppes/npcs/ai/EntityAIZigZagTarget.java @@ -8,6 +8,7 @@ import net.minecraft.pathfinding.PathPoint; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import noppes.npcs.constants.AiMutex; +import noppes.npcs.entity.EntityNPCInterface; public class EntityAIZigZagTarget extends EntityAIBase { private EntityCreature theEntity; @@ -82,6 +83,8 @@ public class EntityAIZigZagTarget extends EntityAIBase { * Updates the task */ public void updateTask() { - this.theEntity.getLookHelper().setLookPositionWithEntity(targetEntity, 30.0F, 30.0F); + if (!(this.theEntity instanceof EntityNPCInterface) || !((EntityNPCInterface) this.theEntity).abilities.isRotationLocked()) { + this.theEntity.getLookHelper().setLookPositionWithEntity(targetEntity, 30.0F, 30.0F); + } } } diff --git a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java index 16389f74d..9e6366fdf 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java @@ -1693,7 +1693,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti } /** - * 1: walking, 2:interacting, 4:attacking, 8:killed + * 1: walking, 2:interacting, 4:attacking, 8:killed, 16:rotationLocked */ public boolean getBoolFlag(int id) { return (dataWatcher.getWatchableObjectInt(15) & id) != 0;