From 24e0be99f3ece43a5eb7d9f70691f663d5afabab Mon Sep 17 00:00:00 2001 From: Under97 <66751151+Underplayer97@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:06:43 -0500 Subject: [PATCH] The final couple updates... The end is nigh... --- .../entity/ai/AmalgamateAttackGoal.java | 79 +++++++++++ .../entity/ai/ErebusAttackGoal.java | 5 +- .../entity/ai/GrimsleyAttackGoal.java | 79 +++++++++++ .../entity/boss/AmalgamateEntity.java | 126 ++++++++++++++++-- .../entity/boss/ErebusEntity.java | 50 ++++++- .../entity/boss/GrimsleyEntity.java | 108 ++++++++++++++- 6 files changed, 423 insertions(+), 24 deletions(-) create mode 100644 src/main/java/net/underplayer97/ResonantEnemies/entity/ai/AmalgamateAttackGoal.java create mode 100644 src/main/java/net/underplayer97/ResonantEnemies/entity/ai/GrimsleyAttackGoal.java diff --git a/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/AmalgamateAttackGoal.java b/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/AmalgamateAttackGoal.java new file mode 100644 index 0000000..ed0f419 --- /dev/null +++ b/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/AmalgamateAttackGoal.java @@ -0,0 +1,79 @@ +package net.underplayer97.ResonantEnemies.entity.ai; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.goal.Goal; +import net.underplayer97.ResonantEnemies.entity.boss.AmalgamateEntity; +import net.underplayer97.ResonantEnemies.entity.boss.GrimsleyEntity; + +import java.util.EnumSet; + +public class AmalgamateAttackGoal extends Goal { + private final AmalgamateEntity entity; + private LivingEntity target; + private final double maxSearchDistance; + + public AmalgamateAttackGoal(AmalgamateEntity entity, double maxSearchDistance) { + this.entity = entity; + this.maxSearchDistance = maxSearchDistance; + setControls(EnumSet.of(Control.MOVE, Control.LOOK)); + } + + @Override + public void start() { + entity.setPrimaryAttackCooldown(Math.max(entity.getPrimaryAttackCooldown(), 20)); + target = entity.getTarget(); + } + + @Override + public boolean canStart() { + if (!entity.canTarget(entity.getTarget())){ + entity.setTarget(null); + return false; + } + + target = entity.getTarget(); + return target != null && (entity.squaredDistanceTo(target) < maxSearchDistance); + } + + @Override + public boolean shouldContinue() { + if (target == null) return false; + if (!target.isAlive()) return false; + return !entity.getNavigation().isIdle() || canStart(); + } + + @Override + public void stop() { + target = null; + entity.setTarget(null); + entity.getNavigation().stop(); + } + + @Override + public boolean shouldRunEveryTick() { + return false; + } + + @Override + public void tick() { + if (target.isRemoved()) { + stop(); + return; + } + + entity.setSprinting(true); + entity.getLookControl().lookAt(target); + double attackDistance = entity.getWidth() * 2.0f * (entity.getWidth() * 2.0f); + double distance = entity.squaredDistanceTo(target); + entity.getNavigation().startMovingTo(target, 1); + boolean doesCollide = entity.doesCollide(entity.getBoundingBox(), target.getBoundingBox()); + + //if(entity.getSpecialAttackCooldown() == 0 && (distance > attackDistance * 4 || distance < attackDistance)) { + // entity.getLookControl().lookAt(target); + // //entity.shoot(); + //} + + if (doesCollide) entity.meleeAttack(target); + + } +} diff --git a/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/ErebusAttackGoal.java b/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/ErebusAttackGoal.java index 74bccb6..08e1cd1 100644 --- a/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/ErebusAttackGoal.java +++ b/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/ErebusAttackGoal.java @@ -50,7 +50,7 @@ public void stop() { @Override public boolean shouldRunEveryTick() { - return true; + return false; } @Override @@ -65,13 +65,14 @@ public void tick() { double attackDistance = entity.getWidth() * 2.0f * (entity.getWidth() * 2.0f); double distance = entity.squaredDistanceTo(target); entity.getNavigation().startMovingTo(target, 1); + boolean doesCollide = entity.doesCollide(entity.getBoundingBox(), target.getBoundingBox()); //if(entity.getSpecialAttackCooldown() == 0 && (distance > attackDistance * 4 || distance < attackDistance)) { // entity.getLookControl().lookAt(target); // //entity.shoot(); //} - if (entity.collides()) entity.meleeAttack(target); + if (doesCollide) entity.meleeAttack(target); } } diff --git a/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/GrimsleyAttackGoal.java b/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/GrimsleyAttackGoal.java new file mode 100644 index 0000000..28a52f4 --- /dev/null +++ b/src/main/java/net/underplayer97/ResonantEnemies/entity/ai/GrimsleyAttackGoal.java @@ -0,0 +1,79 @@ +package net.underplayer97.ResonantEnemies.entity.ai; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.goal.Goal; +import net.underplayer97.ResonantEnemies.entity.boss.ErebusEntity; +import net.underplayer97.ResonantEnemies.entity.boss.GrimsleyEntity; + +import java.util.EnumSet; + +public class GrimsleyAttackGoal extends Goal { + private final GrimsleyEntity entity; + private LivingEntity target; + private final double maxSearchDistance; + + public GrimsleyAttackGoal(GrimsleyEntity entity, double maxSearchDistance) { + this.entity = entity; + this.maxSearchDistance = maxSearchDistance; + setControls(EnumSet.of(Control.MOVE, Control.LOOK)); + } + + @Override + public void start() { + entity.setPrimaryAttackCooldown(Math.max(entity.getPrimaryAttackCooldown(), 20)); + target = entity.getTarget(); + } + + @Override + public boolean canStart() { + if (!entity.canTarget(entity.getTarget())){ + entity.setTarget(null); + return false; + } + + target = entity.getTarget(); + return target != null && (entity.squaredDistanceTo(target) < maxSearchDistance); + } + + @Override + public boolean shouldContinue() { + if (target == null) return false; + if (!target.isAlive()) return false; + return !entity.getNavigation().isIdle() || canStart(); + } + + @Override + public void stop() { + target = null; + entity.setTarget(null); + entity.getNavigation().stop(); + } + + @Override + public boolean shouldRunEveryTick() { + return false; + } + + @Override + public void tick() { + if (target.isRemoved()) { + stop(); + return; + } + + entity.setSprinting(true); + entity.getLookControl().lookAt(target); + double attackDistance = entity.getWidth() * 2.0f * (entity.getWidth() * 2.0f); + double distance = entity.squaredDistanceTo(target); + entity.getNavigation().startMovingTo(target, 1); + boolean doesCollide = entity.doesCollide(entity.getBoundingBox(), target.getBoundingBox()); + + //if(entity.getSpecialAttackCooldown() == 0 && (distance > attackDistance * 4 || distance < attackDistance)) { + // entity.getLookControl().lookAt(target); + // //entity.shoot(); + //} + + if (doesCollide) entity.meleeAttack(target); + + } +} diff --git a/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/AmalgamateEntity.java b/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/AmalgamateEntity.java index 2e38284..47c40c1 100644 --- a/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/AmalgamateEntity.java +++ b/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/AmalgamateEntity.java @@ -1,16 +1,27 @@ package net.underplayer97.ResonantEnemies.entity.boss; import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.ai.goal.ActiveTargetGoal; import net.minecraft.entity.ai.goal.AttackGoal; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.boss.BossBar; +import net.minecraft.entity.data.DataTracker; +import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; +import net.minecraft.util.function.BooleanBiFunction; +import net.minecraft.util.math.Box; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.World; +import net.underplayer97.ResonantEnemies.entity.ai.AmalgamateAttackGoal; +import net.underplayer97.ResonantEnemies.entity.ai.ErebusAttackGoal; +import net.underplayer97.ResonantEnemies.entity.util.ModAttributes; import software.bernie.geckolib3.core.IAnimatable; import software.bernie.geckolib3.core.PlayState; import software.bernie.geckolib3.core.builder.AnimationBuilder; @@ -20,16 +31,34 @@ import software.bernie.geckolib3.core.manager.AnimationFactory; import software.bernie.geckolib3.util.GeckoLibUtil; +import javax.annotation.Nullable; import java.awt.*; public class AmalgamateEntity extends AbstractBossEntity implements IAnimatable { - private final AnimationFactory factory = GeckoLibUtil.createFactory(this); - public int ticksSinceDeath; boolean isDead = false; + public int ticksSinceDeath; + private final AnimationFactory factory = GeckoLibUtil.createFactory(this); + private static final TrackedData PRIMARY_ATTACK_COOLDOWN = DataTracker.registerData(AmalgamateEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData SPECIAL_ATTACK_COOLDOWN = DataTracker.registerData(AmalgamateEntity.class, TrackedDataHandlerRegistry.INTEGER); + public static final TrackedData ATTACK_TYPE = DataTracker.registerData(AmalgamateEntity.class, TrackedDataHandlerRegistry.INTEGER); + public int primaryAttackDuration; + public int specialAttackDuration = 20; + boolean shoot; + boolean summoned; public AmalgamateEntity(EntityType entityType, World world) { super(entityType, world); + primaryAttackDuration = 10; + + } + + @Override + protected void initGoals() { + this.goalSelector.add(1, new AmalgamateAttackGoal(this, 250)); + + this.targetSelector.add(1, new ActiveTargetGoal<>(this, PlayerEntity.class, true)); + } public static DefaultAttributeContainer.Builder setAttributes() { @@ -40,8 +69,89 @@ public static DefaultAttributeContainer.Builder setAttributes() { .add(EntityAttributes.GENERIC_ATTACK_SPEED, 2.0f) .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 50.0f) .add(EntityAttributes.GENERIC_ATTACK_KNOCKBACK, 4.0f) - .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25f) - .add(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, 1.0f); + .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.15f) + .add(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, 1.0f) + .add(ModAttributes.EREBUS_SPECIAL_ATTACK_COOLDOWN, 6.0f) + .add(ModAttributes.EREBUS_PRIMARY_ATTACK_COOLDOWN, 2.0f); + } + + + public void meleeAttack(LivingEntity target) { + setPrimaryAttackCooldown(getMaxPrimaryAttackCooldown()); + setAttackType(random.nextInt(3)+1); + if (target != null) { + Box targetBox = target.getBoundingBox(); + if (doesCollide(targetBox, getBoundingBox())) tryAttack(target); + } + } + + public boolean doesCollide(Box box1, Box box2) { + VoxelShape voxelShape = VoxelShapes.cuboid(box1); + VoxelShape voxelShape2 = VoxelShapes.cuboid(box2); + return VoxelShapes.matchesAnywhere(voxelShape2, voxelShape, BooleanBiFunction.AND); + } + + + @Override + public boolean canTarget(@Nullable LivingEntity target) { + if (target == null) return false; + return super.canTarget(target); + } + + @Override + protected void initDataTracker() { + super.initDataTracker(); + dataTracker.startTracking(PRIMARY_ATTACK_COOLDOWN, 0); + dataTracker.startTracking(SPECIAL_ATTACK_COOLDOWN, 0); + dataTracker.startTracking(ATTACK_TYPE, 1); + } + + public int getAttackType() { + return dataTracker.get(ATTACK_TYPE); + } + + public void setAttackType(int state) { + dataTracker.set(ATTACK_TYPE,state); + } + + public boolean isPrimaryAttack() { + return getPrimaryAttackCooldown() > getMaxPrimaryAttackCooldown() - primaryAttackDuration; + } + + public int getPrimaryAttackCooldown() { + return dataTracker.get(PRIMARY_ATTACK_COOLDOWN); + } + + public void setPrimaryAttackCooldown(int state) { + dataTracker.set(PRIMARY_ATTACK_COOLDOWN, state); + } + + public int getMaxPrimaryAttackCooldown() { + return (int) (getAttributeValue(ModAttributes.EREBUS_PRIMARY_ATTACK_COOLDOWN)); + } + + public boolean isSpecialAttack() { + return getSpecialAttackCooldown() > getMaxSpecialAtackCooldown() - specialAttackDuration; + } + + public int getSpecialAttackCooldown() { + return dataTracker.get(SPECIAL_ATTACK_COOLDOWN); + } + + public void setSpecialAttackCooldown(int state) { + dataTracker.set(PRIMARY_ATTACK_COOLDOWN, state); + } + + public int getMaxSpecialAtackCooldown() { + return (int) (getAttributeValue(ModAttributes.EREBUS_SPECIAL_ATTACK_COOLDOWN)); + } + + @Override + public void tick() { + super.tick(); + + if (getPrimaryAttackCooldown() > 0) setPrimaryAttackCooldown(getPrimaryAttackCooldown() - 1); + if (getSpecialAttackCooldown() > 0) setSpecialAttackCooldown(getSpecialAttackCooldown() - 1); } @Override @@ -83,14 +193,6 @@ private PlayState attackPredicate(AnimationEvent even return PlayState.STOP; } - @Override - protected void initGoals() { - this.goalSelector.add(1, new AttackGoal(this)); - - this.targetSelector.add(1, new ActiveTargetGoal<>(this, PlayerEntity.class, true)); - - } - @Override public void registerControllers(AnimationData animationData) { animationData.addAnimationController(new AnimationController(this, "controller", diff --git a/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/ErebusEntity.java b/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/ErebusEntity.java index c9aff3f..1a0022a 100644 --- a/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/ErebusEntity.java +++ b/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/ErebusEntity.java @@ -21,10 +21,13 @@ import net.minecraft.particle.ParticleTypes; import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; +import net.minecraft.util.function.BooleanBiFunction; import net.minecraft.util.math.Box; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3f; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.GameRules; import net.minecraft.world.World; import net.underplayer97.ResonantEnemies.entity.ai.ErebusAttackGoal; @@ -44,6 +47,9 @@ import software.bernie.geckolib3.core.manager.AnimationFactory; import software.bernie.geckolib3.util.GeckoLibUtil; +import javax.annotation.Nullable; +import java.util.function.Function; + public class ErebusEntity extends AbstractBossEntity implements IAnimatable { private final AnimationFactory factory = GeckoLibUtil.createFactory(this); @@ -51,8 +57,9 @@ public class ErebusEntity extends AbstractBossEntity implements IAnimatable { private float lastScale; private static final TrackedData PRIMARY_ATTACK_COOLDOWN = DataTracker.registerData(ErebusEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData SPECIAL_ATTACK_COOLDOWN = DataTracker.registerData(ErebusEntity.class, TrackedDataHandlerRegistry.INTEGER); - protected int primaryAttackDuration = 20; - protected int specialAttackDuration = 20; + public static final TrackedData ATTACK_TYPE = DataTracker.registerData(ErebusEntity.class, TrackedDataHandlerRegistry.INTEGER); + public int primaryAttackDuration; + public int specialAttackDuration = 20; boolean shoot; boolean isDead = false; boolean summoned; @@ -60,6 +67,9 @@ public class ErebusEntity extends AbstractBossEntity implements IAnimatable { public ErebusEntity(EntityType entityType, World world) { super(entityType, world); this.setHealth(this.getMaxHealth()); + + primaryAttackDuration = 10; + } //TODO: Add spawn and attack animations. Custom beam attacks with animation setup - MIGHT NOT HAVE ENOUGH TIME @@ -81,17 +91,32 @@ public static DefaultAttributeContainer.Builder setAttributes() { @Override protected void initGoals() { - this.goalSelector.add(1, new AttackGoal(this)); + this.goalSelector.add(1, new ErebusAttackGoal(this, 250)); this.targetSelector.add(1, new ActiveTargetGoal<>(this, PlayerEntity.class, true)); } + @Override + public boolean canTarget(@Nullable LivingEntity target) { + if (target == null) return false; + return super.canTarget(target); + } + @Override protected void initDataTracker() { super.initDataTracker(); dataTracker.startTracking(PRIMARY_ATTACK_COOLDOWN, 0); dataTracker.startTracking(SPECIAL_ATTACK_COOLDOWN, 0); + dataTracker.startTracking(ATTACK_TYPE, 1); + } + + public int getAttackType() { + return dataTracker.get(ATTACK_TYPE); + } + + public void setAttackType(int state) { + dataTracker.set(ATTACK_TYPE,state); } public boolean isPrimaryAttack() { @@ -157,10 +182,10 @@ void setShoot(boolean shoot) { public void meleeAttack(LivingEntity target) { setPrimaryAttackCooldown(getMaxPrimaryAttackCooldown()); - //setAttackType(random.nextInt(3)+1) + setAttackType(random.nextInt(3)+1); if (target != null) { Box targetBox = target.getBoundingBox(); - if (collides()) tryAttack(target); + if (doesCollide(targetBox, getBoundingBox())) tryAttack(target); } } @@ -207,6 +232,7 @@ public void onSummoned() { } private PlayState predicate(AnimationEvent event) { + event.getController().setAnimationSpeed(1); if (isDead){ event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.erebus.defeat", false)); return PlayState.CONTINUE; @@ -218,12 +244,16 @@ private PlayState predicate(AnimationEvent event) { event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.erebus.idle", true)); return PlayState.CONTINUE; + } private PlayState attackPredicate(AnimationEvent event) { - if (this.handSwinging) { + + if (isAttacking()) { + event.getController().setAnimationSpeed(2); event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.erebus.slam", false)); - this.handSwinging = false; + //attacking = false; + //return PlayState.CONTINUE; } event.getController().markNeedsReload(); @@ -243,6 +273,12 @@ public AnimationFactory getFactory() { return factory; } + public boolean doesCollide(Box box1, Box box2) { + VoxelShape voxelShape = VoxelShapes.cuboid(box1); + VoxelShape voxelShape2 = VoxelShapes.cuboid(box2); + return VoxelShapes.matchesAnywhere(voxelShape2, voxelShape, BooleanBiFunction.AND); + } + //@Override //public void tick() { // super.tick(); diff --git a/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/GrimsleyEntity.java b/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/GrimsleyEntity.java index 2b2b18a..faed474 100644 --- a/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/GrimsleyEntity.java +++ b/src/main/java/net/underplayer97/ResonantEnemies/entity/boss/GrimsleyEntity.java @@ -1,17 +1,27 @@ package net.underplayer97.ResonantEnemies.entity.boss; import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.ai.goal.ActiveTargetGoal; import net.minecraft.entity.ai.goal.AttackGoal; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.boss.BossBar; +import net.minecraft.entity.data.DataTracker; +import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.particle.ParticleTypes; import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; +import net.minecraft.util.function.BooleanBiFunction; +import net.minecraft.util.math.Box; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.World; +import net.underplayer97.ResonantEnemies.entity.ai.ErebusAttackGoal; +import net.underplayer97.ResonantEnemies.entity.ai.GrimsleyAttackGoal; import net.underplayer97.ResonantEnemies.entity.util.ModAttributes; import software.bernie.geckolib3.core.IAnimatable; import software.bernie.geckolib3.core.PlayState; @@ -22,14 +32,26 @@ import software.bernie.geckolib3.core.manager.AnimationFactory; import software.bernie.geckolib3.util.GeckoLibUtil; +import javax.annotation.Nullable; + public class GrimsleyEntity extends AbstractBossEntity implements IAnimatable { boolean isDead = false; public int ticksSinceDeath; private final AnimationFactory factory = GeckoLibUtil.createFactory(this); + private static final TrackedData PRIMARY_ATTACK_COOLDOWN = DataTracker.registerData(GrimsleyEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData SPECIAL_ATTACK_COOLDOWN = DataTracker.registerData(GrimsleyEntity.class, TrackedDataHandlerRegistry.INTEGER); + public static final TrackedData ATTACK_TYPE = DataTracker.registerData(GrimsleyEntity.class, TrackedDataHandlerRegistry.INTEGER); + public int primaryAttackDuration; + public int specialAttackDuration = 20; + boolean shoot; + boolean summoned; public GrimsleyEntity(EntityType entityType, World world) { super(entityType, world); + + primaryAttackDuration = 10; + } public static DefaultAttributeContainer.Builder setAttributes() { @@ -40,13 +62,93 @@ public static DefaultAttributeContainer.Builder setAttributes() { .add(EntityAttributes.GENERIC_ATTACK_SPEED, 2.0f) .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 50.0f) .add(EntityAttributes.GENERIC_ATTACK_KNOCKBACK, 4.0f) - .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25f) - .add(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, 1.0f); + .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.2f) + .add(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, 1.0f) + .add(ModAttributes.EREBUS_SPECIAL_ATTACK_COOLDOWN, 6.0f) + .add(ModAttributes.EREBUS_PRIMARY_ATTACK_COOLDOWN, 2.0f); + } + + public void meleeAttack(LivingEntity target) { + setPrimaryAttackCooldown(getMaxPrimaryAttackCooldown()); + setAttackType(random.nextInt(3)+1); + if (target != null) { + Box targetBox = target.getBoundingBox(); + if (doesCollide(targetBox, getBoundingBox())) tryAttack(target); + } + } + + public boolean doesCollide(Box box1, Box box2) { + VoxelShape voxelShape = VoxelShapes.cuboid(box1); + VoxelShape voxelShape2 = VoxelShapes.cuboid(box2); + return VoxelShapes.matchesAnywhere(voxelShape2, voxelShape, BooleanBiFunction.AND); + } + + + @Override + public boolean canTarget(@Nullable LivingEntity target) { + if (target == null) return false; + return super.canTarget(target); + } + + @Override + protected void initDataTracker() { + super.initDataTracker(); + dataTracker.startTracking(PRIMARY_ATTACK_COOLDOWN, 0); + dataTracker.startTracking(SPECIAL_ATTACK_COOLDOWN, 0); + dataTracker.startTracking(ATTACK_TYPE, 1); + } + + public int getAttackType() { + return dataTracker.get(ATTACK_TYPE); + } + + public void setAttackType(int state) { + dataTracker.set(ATTACK_TYPE,state); + } + + public boolean isPrimaryAttack() { + return getPrimaryAttackCooldown() > getMaxPrimaryAttackCooldown() - primaryAttackDuration; + } + + public int getPrimaryAttackCooldown() { + return dataTracker.get(PRIMARY_ATTACK_COOLDOWN); + } + + public void setPrimaryAttackCooldown(int state) { + dataTracker.set(PRIMARY_ATTACK_COOLDOWN, state); + } + + public int getMaxPrimaryAttackCooldown() { + return (int) (getAttributeValue(ModAttributes.EREBUS_PRIMARY_ATTACK_COOLDOWN)); + } + + public boolean isSpecialAttack() { + return getSpecialAttackCooldown() > getMaxSpecialAtackCooldown() - specialAttackDuration; + } + + public int getSpecialAttackCooldown() { + return dataTracker.get(SPECIAL_ATTACK_COOLDOWN); + } + + public void setSpecialAttackCooldown(int state) { + dataTracker.set(PRIMARY_ATTACK_COOLDOWN, state); + } + + public int getMaxSpecialAtackCooldown() { + return (int) (getAttributeValue(ModAttributes.EREBUS_SPECIAL_ATTACK_COOLDOWN)); + } + + @Override + public void tick() { + super.tick(); + + if (getPrimaryAttackCooldown() > 0) setPrimaryAttackCooldown(getPrimaryAttackCooldown() - 1); + if (getSpecialAttackCooldown() > 0) setSpecialAttackCooldown(getSpecialAttackCooldown() - 1); } @Override protected void initGoals() { - this.goalSelector.add(1, new AttackGoal(this)); + this.goalSelector.add(1, new GrimsleyAttackGoal(this, 250)); this.targetSelector.add(1, new ActiveTargetGoal<>(this, PlayerEntity.class, true));