diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index 9fa5e676..a4df31ec 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -7,7 +7,7 @@ import com.minelittlepony.unicopia.ability.magic.Levelled; import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; -import com.minelittlepony.unicopia.entity.ai.WantItNeedItTargetGoal; +import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal; import com.minelittlepony.unicopia.entity.player.PlayerAttributes; @@ -37,10 +37,11 @@ public class Creature extends Living { } public void initAi(GoalSelector goals, GoalSelector targets) { - targets.add(1, new WantItNeedItTargetGoal((MobEntity)entity)); - goals.add(1, new WantItTakeItGoal((MobEntity)entity)); + DynamicTargetGoal targetter = new DynamicTargetGoal((MobEntity)entity); + targets.add(1, targetter); + goals.add(1, new WantItTakeItGoal((MobEntity)entity, targetter)); if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) { - goals.add(3, new BreakHeartGoal((MobEntity)entity)); + goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter)); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/BreakHeartGoal.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/BreakHeartGoal.java index 59b94ffe..eed025fa 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ai/BreakHeartGoal.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/BreakHeartGoal.java @@ -1,95 +1,87 @@ package com.minelittlepony.unicopia.entity.ai; -import java.util.Comparator; import java.util.EnumSet; import java.util.Optional; - -import javax.annotation.Nullable; +import java.util.function.Supplier; import com.minelittlepony.unicopia.entity.FloatingArtefactEntity; import com.minelittlepony.unicopia.item.UItems; -import com.minelittlepony.unicopia.util.VecHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.ai.goal.Goal; import net.minecraft.entity.mob.MobEntity; +import net.minecraft.util.Hand; public class BreakHeartGoal extends Goal { - private final MobEntity mob; + protected final MobEntity mob; - @Nullable - private FloatingArtefactEntity target; + private final DynamicTargetGoal targetter; + private final Supplier> target; - private int cooldown; - - public BreakHeartGoal(MobEntity mob) { + public BreakHeartGoal(MobEntity mob, DynamicTargetGoal targetter) { this.mob = mob; + this.targetter = targetter; this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK)); + + target = targetter.addPredicate(this::canTarget); + } + + protected boolean canTarget(Entity e) { + return !e.removed + && e instanceof FloatingArtefactEntity + && ((FloatingArtefactEntity)e).getStack().getItem() == UItems.CRYSTAL_HEART + && mob.getVisibilityCache().canSee(e); } @Override public boolean canStart() { - Optional item = VecHelper.findInRange(mob, mob.world, mob.getPos(), 16, - e -> !e.removed - && e instanceof FloatingArtefactEntity - && ((FloatingArtefactEntity)e).getStack().getItem() == UItems.CRYSTAL_HEART - && mob.getVisibilityCache().canSee(e) - ) - .stream() - .map(e -> (FloatingArtefactEntity)e) - .sorted(Comparator.comparing((Entity e) -> mob.distanceTo(e))) - .findFirst(); - - if (item.isPresent()) { - this.target = item.get(); - return true; - } - - return false; + return target.get().isPresent(); } @Override public boolean shouldContinue() { - return (target == null || (target.isAlive() && mob.squaredDistanceTo(target) <= 225)) || canStart(); + return target.get().map(mob::squaredDistanceTo).orElse(0D) <= 225 + && (!mob.getNavigation().isIdle() || canStart()); } @Override public void stop() { - target = null; + targetter.stop(); mob.getNavigation().stop(); } @Override public void tick() { - if (target == null || target.removed) { - target = null; - return; - } + target.get().ifPresent(target -> { + mob.getLookControl().lookAt(target, 30, 30); - mob.getLookControl().lookAt(target, 30, 30); + double reach = mob.getWidth() * 2 * mob.getWidth() * 2 * target.getWidth(); + double distance = mob.squaredDistanceTo(target.getX(), target.getY(), target.getZ()); - double reach = mob.getWidth() * 2 * mob.getWidth() * 2; - double distance = mob.squaredDistanceTo(target.getX(), target.getY(), target.getZ()); + attackTarget(target, reach, distance); + }); + } + protected void attackTarget(Entity target, double reach, double distance) { double speed = 0.9D; if (distance > reach && distance < 16) { speed = 1.23; } else if (distance < 225) { speed = 1.6; + } else if (distance <= 1) { + speed = 0.5; } mob.getNavigation().startMovingTo(target, speed); - cooldown = Math.max(this.cooldown - 1, 0); - if (target.getY() >= mob.getY() + 2) { reach += 5; } - if (distance <= reach && cooldown <= 0) { - cooldown = 20; + if (distance <= reach) { + mob.swingHand(Hand.MAIN_HAND); mob.tryAttack(target); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/DynamicTargetGoal.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/DynamicTargetGoal.java new file mode 100644 index 00000000..388c6a06 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/DynamicTargetGoal.java @@ -0,0 +1,74 @@ +package com.minelittlepony.unicopia.entity.ai; + +import java.util.Comparator; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import com.minelittlepony.unicopia.util.VecHelper; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.TargetPredicate; +import net.minecraft.entity.ai.goal.Goal; +import net.minecraft.entity.mob.MobEntity; + +public class DynamicTargetGoal extends Goal { + + private final MobEntity mob; + + private int interval; + + private Optional target; + + @Nullable + private Predicate test; + + public DynamicTargetGoal(MobEntity mob) { + this.mob = mob; + } + + public Supplier> addPredicate(Predicate predicate) { + test = test == null ? predicate : predicate.or(test); + + return () -> target.filter(Entity::isAlive).filter(predicate); + } + + public Optional getTarget() { + return target.filter(test).filter(Entity::isAlive); + } + + @Override + public boolean canStart() { + if (interval-- <= 0) { + interval = 20; + + target = VecHelper.findInRange(mob, mob.world, mob.getPos(), 26, test) + .stream() + .sorted(Comparator.comparing(e -> mob.distanceTo(e))) + .findFirst(); + + if (target.isPresent()) { + if (target.get() instanceof LivingEntity) { + mob.setTarget((LivingEntity)target.get()); + } + return true; + } + } + + return false; + } + + @Override + public void stop() { + target = Optional.empty(); + } + + @Override + public boolean shouldContinue() { + LivingEntity target = mob.getTarget(); + return target != null && mob.isTarget(target, TargetPredicate.DEFAULT); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/WantItNeedItTargetGoal.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/WantItNeedItTargetGoal.java deleted file mode 100644 index c95d9d1e..00000000 --- a/src/main/java/com/minelittlepony/unicopia/entity/ai/WantItNeedItTargetGoal.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.minelittlepony.unicopia.entity.ai; - -import java.util.Comparator; -import java.util.Optional; - -import com.minelittlepony.unicopia.EquinePredicates; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.ai.TargetPredicate; -import net.minecraft.entity.ai.goal.Goal; -import net.minecraft.entity.mob.MobEntity; - -public class WantItNeedItTargetGoal extends Goal { - - private final TargetPredicate predicate; - - private final MobEntity mob; - - private int interval; - - public WantItNeedItTargetGoal(MobEntity mob) { - this.predicate = new TargetPredicate() - .setBaseMaxDistance(64) - .setPredicate(EquinePredicates.HAS_WANT_IT_NEED_IT); - this.mob = mob; - } - - @Override - public boolean canStart() { - if (interval-- <= 0) { - interval = 20; - Optional target = mob.world.getOtherEntities(mob, mob.getBoundingBox().expand(16, 16, 16), - e -> e instanceof LivingEntity && predicate.test(mob, (LivingEntity)e)) - .stream() - .map(e -> (LivingEntity)e) - .sorted(Comparator.comparing((Entity e) -> mob.distanceTo(e))) - .findFirst(); - - if (target.isPresent()) { - mob.setTarget(target.get()); - return true; - } - } - - return false; - } - - @Override - public boolean shouldContinue() { - LivingEntity target = mob.getTarget(); - return target != null && mob.isTarget(target, TargetPredicate.DEFAULT); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/WantItTakeItGoal.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/WantItTakeItGoal.java index c61b0d57..08920d1b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ai/WantItTakeItGoal.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/WantItTakeItGoal.java @@ -1,97 +1,42 @@ package com.minelittlepony.unicopia.entity.ai; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.Optional; - -import javax.annotation.Nullable; - import com.minelittlepony.unicopia.AwaitTickQueue; import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.UParticles; -import com.minelittlepony.unicopia.util.VecHelper; - import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.ai.goal.Goal; +import net.minecraft.entity.ai.TargetPredicate; import net.minecraft.entity.mob.MobEntity; import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; -public class WantItTakeItGoal extends Goal { +public class WantItTakeItGoal extends BreakHeartGoal { - private final MobEntity mob; + private final TargetPredicate predicate = new TargetPredicate() + .setBaseMaxDistance(64) + .setPredicate(EquinePredicates.HAS_WANT_IT_NEED_IT); - @Nullable - private LivingEntity target; - @Nullable - private ItemEntity item; + protected int cooldown; - private int cooldown; - - public WantItTakeItGoal(MobEntity mob) { - this.mob = mob; - this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK)); + public WantItTakeItGoal(MobEntity mob, DynamicTargetGoal targetter) { + super(mob, targetter); } @Override - public boolean canStart() { - LivingEntity target = mob.getTarget(); - if (target == null || !EquinePredicates.HAS_WANT_IT_NEED_IT.test(target)) { - - Optional item = VecHelper.findInRange(mob, mob.world, mob.getPos(), 16, - e -> !e.removed && mob.canSee(e) && e instanceof ItemEntity && EnchantmentHelper.getLevel(UEnchantments.WANT_IT_NEED_IT, ((ItemEntity)e).getStack()) > 0) - .stream() - .map(e -> (ItemEntity)e) - .sorted(Comparator.comparing((Entity e) -> mob.distanceTo(e))) - .findFirst(); - - if (item.isPresent()) { - this.item = item.get(); - return true; - } - - return false; - } - - this.target = target; - return true; + protected boolean canTarget(Entity e) { + return (!e.removed && e instanceof ItemEntity && EnchantmentHelper.getLevel(UEnchantments.WANT_IT_NEED_IT, ((ItemEntity)e).getStack()) > 0) + || (e instanceof LivingEntity && predicate.test(mob, (LivingEntity)e)); } @Override - public boolean shouldContinue() { - return (target == null || ( - target.isAlive() - && EquinePredicates.HAS_WANT_IT_NEED_IT.test(target) - && mob.squaredDistanceTo(target) <= 225)) - && (item == null || item.isAlive()) - && (!mob.getNavigation().isIdle() || canStart()); - } - - @Override - public void stop() { - target = null; - item = null; - mob.getNavigation().stop(); - } - - @Override - public void tick() { - if (target == null && (item == null || item.removed)) { - return; - } - - Entity targetEntity = target == null ? item : target; - - mob.getLookControl().lookAt(targetEntity, 30, 30); - - double reach = mob.getWidth() * 2 * mob.getWidth() * 2; - double distance = mob.squaredDistanceTo(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ()); + protected void attackTarget(Entity target, double reach, double distance) { + ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, mob, 0.2F), mob, 1); double speed = 0.8D; @@ -100,22 +45,25 @@ public class WantItTakeItGoal extends Goal { } else if (distance < 225) { speed = 0.6; } - speed *= 2; + if (Math.abs(reach - distance) > 1) { + speed *= 2; + } - ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, mob, 0.2F), mob, 1); + mob.getNavigation().startMovingTo(target, speed); - mob.getNavigation().startMovingTo(targetEntity, speed); + cooldown = Math.max(cooldown - 1, 0); - cooldown = Math.max(this.cooldown - 1, 0); if (distance <= reach) { - if (target != null) { + if (target instanceof LivingEntity) { if (cooldown <= 0) { cooldown = 20; mob.tryAttack(target); + mob.swingHand(Hand.MAIN_HAND); if (mob.world.random.nextInt(20) == 0) { + for (EquipmentSlot slot : EquipmentSlot.values()) { - ItemStack stack = target.getEquippedStack(slot); + ItemStack stack = ((LivingEntity)target).getEquippedStack(slot); if (EnchantmentHelper.getLevel(UEnchantments.WANT_IT_NEED_IT, stack) > 0) { target.equipStack(slot, ItemStack.EMPTY); AwaitTickQueue.scheduleTask(mob.world, w -> { @@ -125,9 +73,11 @@ public class WantItTakeItGoal extends Goal { } } } - } else { - ItemStack stack = item.getStack(); + } else if (target instanceof ItemEntity) { AwaitTickQueue.scheduleTask(mob.world, w -> { + ItemEntity item = (ItemEntity)target; + ItemStack stack = item.getStack(); + if (!item.removed) { mob.tryEquip(stack); mob.method_29499(item);