From 9784c0ed626eff863f01c0871935605750d0285f Mon Sep 17 00:00:00 2001 From: craisinlord Date: Mon, 22 Jun 2026 22:45:41 -0500 Subject: [PATCH] Improved basilisk AI and attack --- .../antarchy/config/AntarchySettings.java | 4 +- .../entity/basilisk/BasiliskEntity.java | 81 ++++++++++++++----- .../entity/nightmare/NightmareEntity.java | 12 ++- .../animations/basilisk.animation.json | 5 ++ 4 files changed, 79 insertions(+), 23 deletions(-) diff --git a/common/src/main/java/com/craisinlord/antarchy/config/AntarchySettings.java b/common/src/main/java/com/craisinlord/antarchy/config/AntarchySettings.java index 80750f0f..e1723a0d 100644 --- a/common/src/main/java/com/craisinlord/antarchy/config/AntarchySettings.java +++ b/common/src/main/java/com/craisinlord/antarchy/config/AntarchySettings.java @@ -147,8 +147,8 @@ public final class AntarchySettings { private static boolean basiliskPetrifyingGazeEnabled = true; private static int basiliskSpawnMaxLightLevel = 5; private static double basiliskHealth = 150.0D; - private static double basiliskAttackDamage = 18.0D; - private static double basiliskMovementSpeed = 0.35D; + private static double basiliskAttackDamage = 8.0D; + private static double basiliskMovementSpeed = 0.30D; private static double basiliskArmor = 6.0D; private static double basiliskKnockbackResistance = 0.5D; private static double basiliskFollowRange = 28.0D; diff --git a/common/src/main/java/com/craisinlord/antarchy/content/entity/basilisk/BasiliskEntity.java b/common/src/main/java/com/craisinlord/antarchy/content/entity/basilisk/BasiliskEntity.java index aca22bed..6c3f4b60 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/entity/basilisk/BasiliskEntity.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/entity/basilisk/BasiliskEntity.java @@ -13,7 +13,10 @@ import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.Difficulty; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.core.Holder; +import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; @@ -71,11 +74,12 @@ public class BasiliskEntity extends Monster implements GeoEntity { private static final RawAnimation ATTACK_ANIM = RawAnimation.begin().thenPlay("attack"); private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("death"); - private static final float TURN_RATE_DEG_PER_TICK = 5.0F; + private static final float TURN_RATE_DEG_PER_TICK = 10.0F; private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this); private int attackAnimTicks = 0; + private boolean attackDamagePending = false; private int hissCooldown = AntarchySettings.basiliskHissCooldownTicks(); private int hissChargeTimer = 0; @@ -148,23 +152,34 @@ public class BasiliskEntity extends Monster implements GeoEntity { if (hurt) { this.level().broadcastEntityEvent(this, ATTACK_ENTITY_EVENT); - this.playSound(AntarchySoundEvents.BASILISK_BITE.get(), 1.1F, 0.95F + this.random.nextFloat() * 0.08F); } return hurt; } private void performAoeAttack() { + if (this.level().isClientSide) return; + // Start the animation; damage fires later in tick() when attackAnimTicks reaches the damage threshold + this.attackAnimTicks = AntarchySettings.basiliskAttackAnimTicks(); + this.attackDamagePending = true; + this.level().broadcastEntityEvent(this, ATTACK_ENTITY_EVENT); + } + + private void tickAoeDamage() { + if (!this.attackDamagePending) return; + if (this.attackAnimTicks > AntarchySettings.basiliskAttackDamageTick()) return; if (!(this.level() instanceof ServerLevel serverLevel)) return; - double attackReach = AntarchySettings.basiliskAttackReach(); - Vec3 forward = Vec3.directionFromRotation(0, this.getYRot()); + this.attackDamagePending = false; + + Vec3 forward = Vec3.directionFromRotation(0, this.yBodyRot); Vec3 right = new Vec3(-forward.z, 0, forward.x); Vec3 origin = this.position(); + double attackReach = AntarchySettings.basiliskAttackReach(); List candidates = this.level().getEntitiesOfClass( LivingEntity.class, - this.getBoundingBox().inflate(Math.max(4.0D, attackReach + 1.5D)), + this.getBoundingBox().inflate(Math.max(8.0D, attackReach + 3.5D)), e -> e != this && e.isAlive() ); @@ -173,16 +188,15 @@ public class BasiliskEntity extends Monster implements GeoEntity { Vec3 toEntity = entity.position().subtract(origin); double fwdDist = toEntity.dot(forward); double sideDist = toEntity.dot(right); - // Forward bite volume measured from the basilisk's center. - if (fwdDist >= 1.0 && fwdDist <= attackReach && Math.abs(sideDist) <= 1.5) { + double upDist = toEntity.y; + if (fwdDist >= 2.0 && fwdDist <= 7.0 && Math.abs(sideDist) <= 2.25 && upDist >= -1.0 && upDist <= 3.0) { if (entity.hurt(AntarchyDamageSources.basiliskBite(serverLevel, this), (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE))) { hitAnything = true; } } } - - this.level().broadcastEntityEvent(this, ATTACK_ENTITY_EVENT); + if (hitAnything) { this.playSound(AntarchySoundEvents.BASILISK_BITE.get(), 1.1F, 0.95F + this.random.nextFloat() * 0.08F); } @@ -207,6 +221,7 @@ public class BasiliskEntity extends Monster implements GeoEntity { this.tickPlayerPetrification(); this.tickPreyPetrification(); + this.tickAoeDamage(); this.updateAnimationState(); } @@ -399,16 +414,13 @@ public class BasiliskEntity extends Monster implements GeoEntity { } private PlayState mainController(AnimationState state) { - if (this.getAnimationState() == ANIM_DEATH) { + if (this.isDeadOrDying()) { return state.setAndContinue(DEATH_ANIM); } - if (this.getAnimationState() == ANIM_ATTACK) { + if (this.attackAnimTicks > 0) { return state.setAndContinue(ATTACK_ANIM); } - if (this.getAnimationState() == ANIM_WALK) { - return state.setAndContinue(WALK_ANIM); - } - if (state.isMoving()) { + if (this.getAnimationState() == ANIM_WALK || state.isMoving()) { return state.setAndContinue(WALK_ANIM); } return state.setAndContinue(IDLE_ANIM); @@ -434,6 +446,7 @@ public class BasiliskEntity extends Monster implements GeoEntity { if (!this.level().isClientSide) { this.setAnimationState(ANIM_DEATH); this.attackAnimTicks = 0; + this.attackDamagePending = false; this.hissChargeTimer = 0; this.pendingTargetId = null; this.getNavigation().stop(); @@ -494,9 +507,22 @@ public class BasiliskEntity extends Monster implements GeoEntity { return super.canAttack(target); } + @Override + public float maxUpStep() { + return 1.5F; + } + + @Override + public boolean canBeAffected(MobEffectInstance effectInstance) { + Holder effect = effectInstance.getEffect(); + if (effect == MobEffects.POISON) return false; + if (effect == AntarchyObjects.PARALYZED_EFFECT.get()) return false; + return super.canBeAffected(effectInstance); + } + @Override public boolean isWithinMeleeAttackRange(LivingEntity target) { - double reach = AntarchySettings.basiliskAttackReach(); + double reach = AntarchySettings.basiliskAttackReach() + 4.0; return this.distanceToSqr(target) <= reach * reach; } @@ -560,16 +586,33 @@ public class BasiliskEntity extends Monster implements GeoEntity { private final class BasiliskMeleeAttackGoal extends MeleeAttackGoal { private BasiliskMeleeAttackGoal() { - super(BasiliskEntity.this, 1.1D, true); + super(BasiliskEntity.this, 1.2D, true); } @Override public void tick() { - if (BasiliskEntity.this.hissChargeTimer > 0) { - BasiliskEntity.this.getNavigation().stop(); + LivingEntity target = BasiliskEntity.this.getTarget(); + if (target != null) { + BasiliskEntity.this.getLookControl().setLookAt(target, 30.0F, 30.0F); + } + + if (BasiliskEntity.this.hissChargeTimer > 0 || BasiliskEntity.this.attackAnimTicks > 0) { + this.stopMovement(); return; } + super.tick(); + + // If we're in range after super ran, kill movement so the basilisk stops and bites + if (target != null && BasiliskEntity.this.isWithinMeleeAttackRange(target)) { + this.stopMovement(); + } + } + + private void stopMovement() { + BasiliskEntity.this.getNavigation().stop(); + BasiliskEntity.this.setSpeed(0.0F); + BasiliskEntity.this.setZza(0.0F); } @Override diff --git a/common/src/main/java/com/craisinlord/antarchy/content/entity/nightmare/NightmareEntity.java b/common/src/main/java/com/craisinlord/antarchy/content/entity/nightmare/NightmareEntity.java index 71f827f5..6eaef628 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/entity/nightmare/NightmareEntity.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/entity/nightmare/NightmareEntity.java @@ -560,7 +560,9 @@ public class NightmareEntity extends Monster implements GeoEntity { private boolean shouldUseFlight() { if (this.landingCooldown > 0) return false; LivingEntity target = this.getTarget(); - return target != null && this.distanceToSqr(target) > FLIGHT_ENGAGE_RANGE_SQR; + return target != null + && this.distanceToSqr(target) > FLIGHT_ENGAGE_RANGE_SQR + && !this.isTooCloseToCeiling(); } private boolean canStartAttackOn(LivingEntity target) { @@ -745,7 +747,8 @@ public class NightmareEntity extends Monster implements GeoEntity { LivingEntity target = NightmareEntity.this.getTarget(); return target != null && NightmareEntity.this.landingCooldown <= 0 - && NightmareEntity.this.distanceToSqr(target) > FLIGHT_ENGAGE_RANGE_SQR; + && NightmareEntity.this.distanceToSqr(target) > FLIGHT_ENGAGE_RANGE_SQR + && !NightmareEntity.this.isTooCloseToCeiling(); } @Override @@ -770,6 +773,11 @@ public class NightmareEntity extends Monster implements GeoEntity { public void tick() { LivingEntity target = NightmareEntity.this.getTarget(); if (target == null) return; + if (NightmareEntity.this.isTooCloseToCeiling()) { + NightmareEntity.this.flyingToTarget = false; + NightmareEntity.this.getNavigation().stop(); + return; + } if (NightmareEntity.this.attackCooldown <= 0 && NightmareEntity.this.canStartAttackOn(target)) { NightmareEntity.this.startAttack(target); return; diff --git a/common/src/main/resources/assets/antarchy/animations/basilisk.animation.json b/common/src/main/resources/assets/antarchy/animations/basilisk.animation.json index 08c31a7d..c72e0698 100644 --- a/common/src/main/resources/assets/antarchy/animations/basilisk.animation.json +++ b/common/src/main/resources/assets/antarchy/animations/basilisk.animation.json @@ -409,6 +409,11 @@ "attack": { "loop": false, "animation_length": 1, + "sound_effects": { + "0.3333": { + "effect": "antarchy:basilisk_bite|1.1|1.0" + } + }, "bones": { "Basilisk": { "position": {