Fixed sombra ai not attacking other entities

This commit is contained in:
Sollace 2023-09-14 18:05:27 +01:00
parent 63d6e96da4
commit 8cc5416d8f
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
2 changed files with 99 additions and 46 deletions

View file

@ -33,14 +33,16 @@ public class ArenaAttackGoal<E extends MobEntity & ArenaCombatant> extends Attac
@Override @Override
public void stop() { public void stop() {
super.stop(); super.stop();
combatant.setTarget(null);
combatant.getHomePos().ifPresent(home -> { combatant.getHomePos().ifPresent(home -> {
if (!isInArena(home)) {
Path path = combatant.getNavigation().findPathTo(home, 2, (int)combatant.getAreaRadius() * 2); Path path = combatant.getNavigation().findPathTo(home, 2, (int)combatant.getAreaRadius() * 2);
if (path != null) { if (path != null) {
combatant.getNavigation().startMovingAlong(path, combatant.getMovementSpeed() * 2F); combatant.getNavigation().startMovingAlong(path, combatant.getMovementSpeed() * 2F);
} else { } else {
combatant.teleportTo(home.toCenterPos()); var destination = home.toCenterPos();
combatant.teleportTo(destination);
combatant.setPosition(destination);
}
} }
}); });
} }

View file

@ -6,6 +6,7 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableSet;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
@ -30,22 +31,25 @@ import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.MovementType; import net.minecraft.entity.MovementType;
import net.minecraft.entity.ai.goal.ActiveTargetGoal; import net.minecraft.entity.ai.goal.ActiveTargetGoal;
import net.minecraft.entity.ai.goal.FlyGoal;
import net.minecraft.entity.ai.goal.LongDoorInteractGoal; import net.minecraft.entity.ai.goal.LongDoorInteractGoal;
import net.minecraft.entity.ai.goal.LookAroundGoal; import net.minecraft.entity.ai.goal.LookAroundGoal;
import net.minecraft.entity.ai.goal.LookAtEntityGoal; import net.minecraft.entity.ai.goal.LookAtEntityGoal;
import net.minecraft.entity.ai.goal.PounceAtTargetGoal; import net.minecraft.entity.ai.goal.PounceAtTargetGoal;
import net.minecraft.entity.ai.goal.RevengeGoal; import net.minecraft.entity.ai.goal.RevengeGoal;
import net.minecraft.entity.ai.goal.WanderAroundGoal; import net.minecraft.entity.ai.goal.WanderAroundGoal;
import net.minecraft.entity.ai.goal.WanderNearTargetGoal;
import net.minecraft.entity.ai.pathing.BirdNavigation;
import net.minecraft.entity.ai.pathing.BirdPathNodeMaker; import net.minecraft.entity.ai.pathing.BirdPathNodeMaker;
import net.minecraft.entity.ai.pathing.EntityNavigation; import net.minecraft.entity.ai.pathing.EntityNavigation;
import net.minecraft.entity.ai.pathing.MobNavigation; import net.minecraft.entity.ai.pathing.MobNavigation;
import net.minecraft.entity.ai.pathing.Path;
import net.minecraft.entity.ai.pathing.PathNodeNavigator; import net.minecraft.entity.ai.pathing.PathNodeNavigator;
import net.minecraft.entity.ai.pathing.PathNodeType; import net.minecraft.entity.ai.pathing.PathNodeType;
import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.boss.BossBar; import net.minecraft.entity.boss.BossBar;
import net.minecraft.entity.boss.ServerBossBar; import net.minecraft.entity.boss.ServerBossBar;
import net.minecraft.entity.boss.WitherEntity;
import net.minecraft.entity.boss.BossBar.Style; import net.minecraft.entity.boss.BossBar.Style;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.data.DataTracker;
@ -53,6 +57,7 @@ import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.mob.FlyingEntity;
import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.passive.IronGolemEntity; import net.minecraft.entity.passive.IronGolemEntity;
import net.minecraft.entity.passive.MerchantEntity; import net.minecraft.entity.passive.MerchantEntity;
@ -83,8 +88,8 @@ import net.minecraft.world.event.GameEvent;
public class SombraEntity extends HostileEntity implements ArenaCombatant, ParticleSource<SombraEntity> { public class SombraEntity extends HostileEntity implements ArenaCombatant, ParticleSource<SombraEntity> {
static final byte BITE = 70; static final byte BITE = 70;
static final int MAX_BITE_TIME = 20; static final int MAX_BITE_TIME = 20;
static final Predicate<Entity> EFFECT_TARGET_PREDICATE = EntityPredicates.VALID_LIVING_ENTITY static final Predicate<Entity> EFFECT_TARGET_PREDICATE = EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR
.and(EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR) .and(e -> e instanceof PlayerEntity)
.and(e -> !(AbstractDisguiseSpell.getAppearance(e) instanceof SombraEntity)); .and(e -> !(AbstractDisguiseSpell.getAppearance(e) instanceof SombraEntity));
private static final TrackedData<Optional<BlockPos>> HOME_POS = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS); private static final TrackedData<Optional<BlockPos>> HOME_POS = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS);
@ -163,17 +168,18 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
@Override @Override
protected void initGoals() { protected void initGoals() {
goalSelector.add(1, new ArenaAttackGoal<>(this));
goalSelector.add(2, new PounceAtTargetGoal(this, 1.3F));
goalSelector.add(2, new LongDoorInteractGoal(this, true)); goalSelector.add(2, new LongDoorInteractGoal(this, true));
goalSelector.add(5, new FlyGoal(this, 1)); goalSelector.add(2, new WanderNearTargetGoal(this, 1.5F, 32));
goalSelector.add(6, new LookAtEntityGoal(this, PlayerEntity.class, 18F)); goalSelector.add(6, new LookAtEntityGoal(this, LivingEntity.class, 32F));
goalSelector.add(7, new LookAroundGoal(this)); goalSelector.add(7, new LookAroundGoal(this));
goalSelector.add(7, new WanderAroundGoal(this, 1)); goalSelector.add(7, new WanderAroundGoal(this, 1));
goalSelector.add(8, new PounceAtTargetGoal(this, 1.3F));
goalSelector.add(8, new ArenaAttackGoal<>(this));
targetSelector.add(1, new RevengeGoal(this)); targetSelector.add(1, new RevengeGoal(this));
targetSelector.add(2, new ActiveTargetGoal<>(this, PlayerEntity.class, false)); targetSelector.add(2, new ActiveTargetGoal<>(this, PlayerEntity.class, false));
targetSelector.add(3, new ActiveTargetGoal<>(this, MerchantEntity.class, false)); targetSelector.add(3, new ActiveTargetGoal<>(this, MerchantEntity.class, false));
targetSelector.add(3, new ActiveTargetGoal<>(this, IronGolemEntity.class, true)); targetSelector.add(3, new ActiveTargetGoal<>(this, IronGolemEntity.class, true));
targetSelector.add(4, new ActiveTargetGoal<>(this, HostileEntity.class, true));
} }
@Override @Override
@ -185,6 +191,27 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
nodeMaker.setCanEnterOpenDoors(true); nodeMaker.setCanEnterOpenDoors(true);
return new PathNodeNavigator(nodeMaker, range); return new PathNodeNavigator(nodeMaker, range);
} }
@Override
protected boolean canPathDirectlyThrough(Vec3d origin, Vec3d target) {
return BirdNavigation.doesNotCollide(entity, origin, target, true);
}
@Override
protected boolean isAtValidPosition() {
return canSwim() && isInLiquid() || !entity.hasVehicle();
}
@Override
protected Vec3d getPos() {
return entity.getPos();
}
@Override
@Nullable
public Path findPathTo(BlockPos target, int distance) {
return findPathTo(ImmutableSet.of(target), 8, false, distance);
}
}; };
nav.setCanPathThroughDoors(true); nav.setCanPathThroughDoors(true);
nav.setCanSwim(true); nav.setCanSwim(true);
@ -232,10 +259,12 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
} }
if (!isRemoved()) { if (!isRemoved()) {
if (getNavigation().isIdle()) {
if (getBlockPos().getSquaredDistance(homePos.get()) > MathHelper.square(getAreaRadius())) { if (getBlockPos().getSquaredDistance(homePos.get()) > MathHelper.square(getAreaRadius())) {
teleportTo(Vec3d.ofCenter(homePos.get())); teleportTo(Vec3d.ofCenter(homePos.get()));
getNavigation().stop(); getNavigation().stop();
} }
}
prevBiteTime = biteTime; prevBiteTime = biteTime;
if (biteTime > 0) { if (biteTime > 0) {
@ -246,10 +275,6 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
boolean sizeChanging = prevSize != currentSize; boolean sizeChanging = prevSize != currentSize;
prevSize = currentSize; prevSize = currentSize;
tickGrowth(targetSize, sizeChanging); tickGrowth(targetSize, sizeChanging);
if (!hasPositionTarget() && homePos.isPresent()) {
setPositionTarget(homePos.get(), (int)getAreaRadius());
}
} }
super.tick(); super.tick();
@ -258,7 +283,20 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
setVelocity(getVelocity().multiply(1, 0.4, 1)); setVelocity(getVelocity().multiply(1, 0.4, 1));
} }
addVelocity(0, 0.0242F, 0); addVelocity(0, 0.0442F, 0);
LivingEntity target = getTarget();
if (target != null && target.getY() > getY() && getVelocity().getY() < 0.5F) {
float velocityChange = (float)MathHelper.clamp((target.getY() - getY()) * 0.05F, -0.3F, 0.3F);
if (target instanceof WitherEntity || target instanceof FlyingEntity) {
target.addVelocity(0, -velocityChange * 20, 0);
} else {
addVelocity(0, velocityChange, 0);
}
}
if (isDead()) { if (isDead()) {
return; return;
@ -303,12 +341,16 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
} }
} }
if (getTarget() != null && getTarget().isRemoved()) {
setTarget(null);
}
if (getHealth() < getMaxHealth()) { if (getHealth() < getMaxHealth()) {
for (Entity shard : getWorld().getEntitiesByClass(CrystalShardsEntity.class, getBoundingBox().expand(50), EntityPredicates.VALID_ENTITY)) { for (Entity shard : getWorld().getEntitiesByClass(CrystalShardsEntity.class, getBoundingBox().expand(50), EntityPredicates.VALID_ENTITY)) {
if (age % 150 == 0) { if (age % 150 == 0) {
heal(2); heal(2);
}
ParticleUtils.spawnParticle(getWorld(), ParticleUtils.spawnParticle(getWorld(),
new FollowingParticleEffect(UParticles.HEALTH_DRAIN, this, 0.2F) new FollowingParticleEffect(UParticles.HEALTH_DRAIN, this, 0.2F)
.withChild(ParticleTypes.CAMPFIRE_SIGNAL_SMOKE), .withChild(ParticleTypes.CAMPFIRE_SIGNAL_SMOKE),
@ -317,6 +359,7 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
); );
} }
} }
}
getHomePos().ifPresent(this::generateArenaEffects); getHomePos().ifPresent(this::generateArenaEffects);
} }
@ -344,7 +387,7 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
} }
} }
protected void applyAreaEffects(Entity target) { protected void applyAreaEffects(PlayerEntity target) {
if (this.age % 150 == 0) { if (this.age % 150 == 0) {
target.playSound( target.playSound(
random.nextInt(30) == 0 ? USounds.ENTITY_SOMBRA_AMBIENT random.nextInt(30) == 0 ? USounds.ENTITY_SOMBRA_AMBIENT
@ -356,12 +399,11 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
} }
if (this.age % 1000 < 50) { if (this.age % 1000 < 50) {
((LivingEntity)target).addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, 26, 0, true, false)); target.addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, 26, 0, true, false));
((LivingEntity)target).addStatusEffect(new StatusEffectInstance(StatusEffects.DARKNESS, 26, 0, true, false)); target.addStatusEffect(new StatusEffectInstance(StatusEffects.DARKNESS, 26, 0, true, false));
} }
if (getTarget() == null && target instanceof PlayerEntity player && player.distanceTo(this) < getAreaRadius() / 2F) { if (getTarget() == null && target instanceof PlayerEntity player && player.distanceTo(this) < getAreaRadius() / 2F) {
setTarget(player);
if (teleportTo(target.getPos())) { if (teleportTo(target.getPos())) {
setPosition(getPos().add(0, 4, 0)); setPosition(getPos().add(0, 4, 0));
} }
@ -376,9 +418,9 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
protected void generateBodyParticles() { protected void generateBodyParticles() {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
getWorld().addParticle(ParticleTypes.LARGE_SMOKE, getWorld().addParticle(ParticleTypes.LARGE_SMOKE,
random.nextTriangular(getX(), 8), random.nextTriangular(getX(), 3),
random.nextTriangular(getY(), 1), random.nextTriangular(getY(), 3),
random.nextTriangular(getZ(), 8), random.nextTriangular(getZ(), 3),
0, 0,
0, 0,
0 0
@ -397,9 +439,9 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
ParticleUtils.spawnParticle(getWorld(), type, pos, pos.subtract(getPos()).add(0, 0.1, 0).multiply(-0.013)); ParticleUtils.spawnParticle(getWorld(), type, pos, pos.subtract(getPos()).add(0, 0.1, 0).multiply(-0.013));
}); });
} else { } else {
for (Entity target : VecHelper.findInRange(this, getWorld(), home.toCenterPos(), getAreaRadius() - 0.2F, EFFECT_TARGET_PREDICATE)) { VecHelper.findInRange(this, getWorld(), home.toCenterPos(), getAreaRadius() - 0.2F, EFFECT_TARGET_PREDICATE).forEach(e -> {
applyAreaEffects(target); applyAreaEffects((PlayerEntity)e);
} });
} }
} }
@ -442,8 +484,12 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
boolean damaged = super.damage(source, amount); boolean damaged = super.damage(source, amount);
if (!getWorld().isClient) { if (!getWorld().isClient) {
if (source.getAttacker() instanceof PlayerEntity player) { if (source.getAttacker() instanceof LivingEntity attacker) {
teleportRandomly(16); teleportRandomly(6);
if (!(attacker instanceof PlayerEntity player && (player.isCreative() || player.isSpectator()))) {
setTarget(attacker);
}
} }
float targetSize = getScaleFactor(); float targetSize = getScaleFactor();
@ -468,12 +514,10 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
((CrystalShardsEntity)e).setDecaying(true); ((CrystalShardsEntity)e).setDecaying(true);
}); });
for (Entity e : VecHelper.findInRange(this, getWorld(), home.toCenterPos(), getAreaRadius() - 0.2F, EFFECT_TARGET_PREDICATE)) { VecHelper.findInRange(this, getWorld(), home.toCenterPos(), getAreaRadius() - 0.2F, EFFECT_TARGET_PREDICATE).forEach(player -> {
Pony.of(e).ifPresent(pony -> { Pony.of((PlayerEntity)player).getCorruption().set(0);
pony.getCorruption().set(0); UCriteria.DEFEAT_SOMBRA.trigger(player);
UCriteria.DEFEAT_SOMBRA.trigger(e);
}); });
}
}); });
} }
@ -528,6 +572,13 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
@Override @Override
public boolean canTarget(LivingEntity target) { public boolean canTarget(LivingEntity target) {
if (target instanceof PlayerEntity player && (player.isCreative() || player.isSpectator())) {
return false;
}
if (target != null && !target.isRemoved() && target == getTarget()) {
return true;
}
return super.canTarget(target) && getHomePos().filter(home -> target.getPos().isInRange(home.toCenterPos(), getAreaRadius())).isPresent(); return super.canTarget(target) && getHomePos().filter(home -> target.getPos().isInRange(home.toCenterPos(), getAreaRadius())).isPresent();
} }