update mob behaviour for zombies and spooders

This commit is contained in:
2026-07-02 10:20:16 +02:00
parent 9d8cea70dc
commit e973c29bb1
@@ -0,0 +1,91 @@
package net.fretux.adaptivemobs.ai.goals;
import net.fretux.adaptivemobs.ai.AdaptiveAIGoalUtils;
import net.fretux.adaptivemobs.ai.AdaptivePositioningUtils;
import net.fretux.adaptivemobs.ai.AdaptiveTargetingUtils;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.phys.Vec3;
import java.util.EnumSet;
import java.util.List;
import java.util.function.IntSupplier;
public class AdaptiveZombiePackTacticsGoal extends Goal {
private static final double GOLDEN_ANGLE = Math.PI * (3.0D - Math.sqrt(5.0D));
private final Zombie zombie;
private final IntSupplier tierSupplier;
private int cooldown;
public AdaptiveZombiePackTacticsGoal(Zombie zombie, IntSupplier tierSupplier) {
this.zombie = zombie;
this.tierSupplier = tierSupplier;
setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
}
@Override
public boolean canUse() {
int tier = tierSupplier.getAsInt();
LivingEntity target = zombie.getTarget();
return tier >= 4
&& target != null
&& target.isAlive()
&& !zombie.isPassenger()
&& zombie.distanceToSqr(target) <= 9.0D * 9.0D
&& AdaptiveTargetingUtils.nearbyAttackers(zombie, target, 6.0D) >= 3
&& --cooldown <= 0;
}
@Override
public void start() {
int tier = tierSupplier.getAsInt();
cooldown = tier >= 5 ? 8 + zombie.getRandom().nextInt(13) : 18 + zombie.getRandom().nextInt(22);
LivingEntity target = zombie.getTarget();
if (target == null || !target.isAlive()) {
return;
}
zombie.getLookControl().setLookAt(target, 35.0F, 35.0F);
List<Zombie> pack = zombie.level().getEntitiesOfClass(Zombie.class, zombie.getBoundingBox().inflate(6.0D),
other -> other != zombie && other.isAlive() && other.getTarget() == target);
if (pack.isEmpty()) {
return;
}
Vec3 dest = packSlot(target, pack.size() + 1);
dest = dest.add(localSeparation(pack));
if (!AdaptivePositioningUtils.isReasonableGround(zombie, dest)) {
dest = AdaptivePositioningUtils.sidePosition(zombie, target, 2.5D, zombie.getId() % 2 == 0 ? 1.0D : -1.0D,
tier >= 5 ? 0.12D : 0.0D);
}
if (AdaptivePositioningUtils.isReasonableGround(zombie, dest)) {
zombie.getNavigation().moveTo(dest.x, dest.y, dest.z, tier >= 5 ? 1.12D : 1.04D);
AdaptiveAIGoalUtils.debug(zombie, tierSupplier, "zombie pack spread");
}
}
private Vec3 packSlot(LivingEntity target, int packSize) {
double radius = Math.min(4.0D, 2.0D + packSize * 0.18D);
double angle = (Math.floorMod(zombie.getId(), 16) * GOLDEN_ANGLE) + (packSize * 0.17D);
return new Vec3(target.getX() + Math.cos(angle) * radius, target.getY(), target.getZ() + Math.sin(angle) * radius);
}
private Vec3 localSeparation(List<Zombie> pack) {
double pushX = 0.0D;
double pushZ = 0.0D;
for (Zombie other : pack) {
double distSqr = zombie.distanceToSqr(other);
if (distSqr < 0.01D || distSqr > 2.25D) {
continue;
}
Vec3 away = zombie.position().subtract(other.position());
double scale = (2.25D - distSqr) / 2.25D;
pushX += away.x * scale;
pushZ += away.z * scale;
}
return new Vec3(pushX, 0.0D, pushZ);
}
}