Improved basilisk AI and attack
This commit is contained in:
1 parent
3c6c54ebd6
commit
9784c0ed62
4 files changed
+79
-23
No files matched your search
@@ -147,8 +147,8 @@ public final class AntarchySettings {
|
|||||||
private static boolean basiliskPetrifyingGazeEnabled = true;
|
private static boolean basiliskPetrifyingGazeEnabled = true;
|
||||||
private static int basiliskSpawnMaxLightLevel = 5;
|
private static int basiliskSpawnMaxLightLevel = 5;
|
||||||
private static double basiliskHealth = 150.0D;
|
private static double basiliskHealth = 150.0D;
|
||||||
private static double basiliskAttackDamage = 18.0D;
|
private static double basiliskAttackDamage = 8.0D;
|
||||||
private static double basiliskMovementSpeed = 0.35D;
|
private static double basiliskMovementSpeed = 0.30D;
|
||||||
private static double basiliskArmor = 6.0D;
|
private static double basiliskArmor = 6.0D;
|
||||||
private static double basiliskKnockbackResistance = 0.5D;
|
private static double basiliskKnockbackResistance = 0.5D;
|
||||||
private static double basiliskFollowRange = 28.0D;
|
private static double basiliskFollowRange = 28.0D;
|
||||||
|
|||||||
+62
-19
@@ -13,7 +13,10 @@ import net.minecraft.util.Mth;
|
|||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
import net.minecraft.world.Difficulty;
|
import net.minecraft.world.Difficulty;
|
||||||
import net.minecraft.world.damagesource.DamageSource;
|
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.MobEffectInstance;
|
||||||
|
import net.minecraft.world.effect.MobEffects;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.entity.EquipmentSlot;
|
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 ATTACK_ANIM = RawAnimation.begin().thenPlay("attack");
|
||||||
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("death");
|
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 final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
private int attackAnimTicks = 0;
|
private int attackAnimTicks = 0;
|
||||||
|
private boolean attackDamagePending = false;
|
||||||
|
|
||||||
private int hissCooldown = AntarchySettings.basiliskHissCooldownTicks();
|
private int hissCooldown = AntarchySettings.basiliskHissCooldownTicks();
|
||||||
private int hissChargeTimer = 0;
|
private int hissChargeTimer = 0;
|
||||||
@@ -148,23 +152,34 @@ public class BasiliskEntity extends Monster implements GeoEntity {
|
|||||||
|
|
||||||
if (hurt) {
|
if (hurt) {
|
||||||
this.level().broadcastEntityEvent(this, ATTACK_ENTITY_EVENT);
|
this.level().broadcastEntityEvent(this, ATTACK_ENTITY_EVENT);
|
||||||
this.playSound(AntarchySoundEvents.BASILISK_BITE.get(), 1.1F, 0.95F + this.random.nextFloat() * 0.08F);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hurt;
|
return hurt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performAoeAttack() {
|
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;
|
if (!(this.level() instanceof ServerLevel serverLevel)) return;
|
||||||
|
|
||||||
double attackReach = AntarchySettings.basiliskAttackReach();
|
this.attackDamagePending = false;
|
||||||
Vec3 forward = Vec3.directionFromRotation(0, this.getYRot());
|
|
||||||
|
Vec3 forward = Vec3.directionFromRotation(0, this.yBodyRot);
|
||||||
Vec3 right = new Vec3(-forward.z, 0, forward.x);
|
Vec3 right = new Vec3(-forward.z, 0, forward.x);
|
||||||
Vec3 origin = this.position();
|
Vec3 origin = this.position();
|
||||||
|
double attackReach = AntarchySettings.basiliskAttackReach();
|
||||||
|
|
||||||
List<LivingEntity> candidates = this.level().getEntitiesOfClass(
|
List<LivingEntity> candidates = this.level().getEntitiesOfClass(
|
||||||
LivingEntity.class,
|
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()
|
e -> e != this && e.isAlive()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -173,16 +188,15 @@ public class BasiliskEntity extends Monster implements GeoEntity {
|
|||||||
Vec3 toEntity = entity.position().subtract(origin);
|
Vec3 toEntity = entity.position().subtract(origin);
|
||||||
double fwdDist = toEntity.dot(forward);
|
double fwdDist = toEntity.dot(forward);
|
||||||
double sideDist = toEntity.dot(right);
|
double sideDist = toEntity.dot(right);
|
||||||
// Forward bite volume measured from the basilisk's center.
|
double upDist = toEntity.y;
|
||||||
if (fwdDist >= 1.0 && fwdDist <= attackReach && Math.abs(sideDist) <= 1.5) {
|
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),
|
if (entity.hurt(AntarchyDamageSources.basiliskBite(serverLevel, this),
|
||||||
(float) this.getAttributeValue(Attributes.ATTACK_DAMAGE))) {
|
(float) this.getAttributeValue(Attributes.ATTACK_DAMAGE))) {
|
||||||
hitAnything = true;
|
hitAnything = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.level().broadcastEntityEvent(this, ATTACK_ENTITY_EVENT);
|
|
||||||
if (hitAnything) {
|
if (hitAnything) {
|
||||||
this.playSound(AntarchySoundEvents.BASILISK_BITE.get(), 1.1F, 0.95F + this.random.nextFloat() * 0.08F);
|
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.tickPlayerPetrification();
|
||||||
this.tickPreyPetrification();
|
this.tickPreyPetrification();
|
||||||
|
this.tickAoeDamage();
|
||||||
this.updateAnimationState();
|
this.updateAnimationState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,16 +414,13 @@ public class BasiliskEntity extends Monster implements GeoEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private PlayState mainController(AnimationState<BasiliskEntity> state) {
|
private PlayState mainController(AnimationState<BasiliskEntity> state) {
|
||||||
if (this.getAnimationState() == ANIM_DEATH) {
|
if (this.isDeadOrDying()) {
|
||||||
return state.setAndContinue(DEATH_ANIM);
|
return state.setAndContinue(DEATH_ANIM);
|
||||||
}
|
}
|
||||||
if (this.getAnimationState() == ANIM_ATTACK) {
|
if (this.attackAnimTicks > 0) {
|
||||||
return state.setAndContinue(ATTACK_ANIM);
|
return state.setAndContinue(ATTACK_ANIM);
|
||||||
}
|
}
|
||||||
if (this.getAnimationState() == ANIM_WALK) {
|
if (this.getAnimationState() == ANIM_WALK || state.isMoving()) {
|
||||||
return state.setAndContinue(WALK_ANIM);
|
|
||||||
}
|
|
||||||
if (state.isMoving()) {
|
|
||||||
return state.setAndContinue(WALK_ANIM);
|
return state.setAndContinue(WALK_ANIM);
|
||||||
}
|
}
|
||||||
return state.setAndContinue(IDLE_ANIM);
|
return state.setAndContinue(IDLE_ANIM);
|
||||||
@@ -434,6 +446,7 @@ public class BasiliskEntity extends Monster implements GeoEntity {
|
|||||||
if (!this.level().isClientSide) {
|
if (!this.level().isClientSide) {
|
||||||
this.setAnimationState(ANIM_DEATH);
|
this.setAnimationState(ANIM_DEATH);
|
||||||
this.attackAnimTicks = 0;
|
this.attackAnimTicks = 0;
|
||||||
|
this.attackDamagePending = false;
|
||||||
this.hissChargeTimer = 0;
|
this.hissChargeTimer = 0;
|
||||||
this.pendingTargetId = null;
|
this.pendingTargetId = null;
|
||||||
this.getNavigation().stop();
|
this.getNavigation().stop();
|
||||||
@@ -494,9 +507,22 @@ public class BasiliskEntity extends Monster implements GeoEntity {
|
|||||||
return super.canAttack(target);
|
return super.canAttack(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float maxUpStep() {
|
||||||
|
return 1.5F;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canBeAffected(MobEffectInstance effectInstance) {
|
||||||
|
Holder<MobEffect> effect = effectInstance.getEffect();
|
||||||
|
if (effect == MobEffects.POISON) return false;
|
||||||
|
if (effect == AntarchyObjects.PARALYZED_EFFECT.get()) return false;
|
||||||
|
return super.canBeAffected(effectInstance);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isWithinMeleeAttackRange(LivingEntity target) {
|
public boolean isWithinMeleeAttackRange(LivingEntity target) {
|
||||||
double reach = AntarchySettings.basiliskAttackReach();
|
double reach = AntarchySettings.basiliskAttackReach() + 4.0;
|
||||||
return this.distanceToSqr(target) <= reach * reach;
|
return this.distanceToSqr(target) <= reach * reach;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,16 +586,33 @@ public class BasiliskEntity extends Monster implements GeoEntity {
|
|||||||
|
|
||||||
private final class BasiliskMeleeAttackGoal extends MeleeAttackGoal {
|
private final class BasiliskMeleeAttackGoal extends MeleeAttackGoal {
|
||||||
private BasiliskMeleeAttackGoal() {
|
private BasiliskMeleeAttackGoal() {
|
||||||
super(BasiliskEntity.this, 1.1D, true);
|
super(BasiliskEntity.this, 1.2D, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
if (BasiliskEntity.this.hissChargeTimer > 0) {
|
LivingEntity target = BasiliskEntity.this.getTarget();
|
||||||
BasiliskEntity.this.getNavigation().stop();
|
if (target != null) {
|
||||||
|
BasiliskEntity.this.getLookControl().setLookAt(target, 30.0F, 30.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BasiliskEntity.this.hissChargeTimer > 0 || BasiliskEntity.this.attackAnimTicks > 0) {
|
||||||
|
this.stopMovement();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.tick();
|
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
|
@Override
|
||||||
|
|||||||
+10
-2
@@ -560,7 +560,9 @@ public class NightmareEntity extends Monster implements GeoEntity {
|
|||||||
private boolean shouldUseFlight() {
|
private boolean shouldUseFlight() {
|
||||||
if (this.landingCooldown > 0) return false;
|
if (this.landingCooldown > 0) return false;
|
||||||
LivingEntity target = this.getTarget();
|
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) {
|
private boolean canStartAttackOn(LivingEntity target) {
|
||||||
@@ -745,7 +747,8 @@ public class NightmareEntity extends Monster implements GeoEntity {
|
|||||||
LivingEntity target = NightmareEntity.this.getTarget();
|
LivingEntity target = NightmareEntity.this.getTarget();
|
||||||
return target != null
|
return target != null
|
||||||
&& NightmareEntity.this.landingCooldown <= 0
|
&& NightmareEntity.this.landingCooldown <= 0
|
||||||
&& NightmareEntity.this.distanceToSqr(target) > FLIGHT_ENGAGE_RANGE_SQR;
|
&& NightmareEntity.this.distanceToSqr(target) > FLIGHT_ENGAGE_RANGE_SQR
|
||||||
|
&& !NightmareEntity.this.isTooCloseToCeiling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -770,6 +773,11 @@ public class NightmareEntity extends Monster implements GeoEntity {
|
|||||||
public void tick() {
|
public void tick() {
|
||||||
LivingEntity target = NightmareEntity.this.getTarget();
|
LivingEntity target = NightmareEntity.this.getTarget();
|
||||||
if (target == null) return;
|
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)) {
|
if (NightmareEntity.this.attackCooldown <= 0 && NightmareEntity.this.canStartAttackOn(target)) {
|
||||||
NightmareEntity.this.startAttack(target);
|
NightmareEntity.this.startAttack(target);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -409,6 +409,11 @@
|
|||||||
"attack": {
|
"attack": {
|
||||||
"loop": false,
|
"loop": false,
|
||||||
"animation_length": 1,
|
"animation_length": 1,
|
||||||
|
"sound_effects": {
|
||||||
|
"0.3333": {
|
||||||
|
"effect": "antarchy:basilisk_bite|1.1|1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"bones": {
|
"bones": {
|
||||||
"Basilisk": {
|
"Basilisk": {
|
||||||
"position": {
|
"position": {
|
||||||
|
|||||||
Reference in new issue
Block a user