Unicopia/src/main/java/com/minelittlepony/unicopia/entity/SombraEntity.java

635 lines
23 KiB
Java
Raw Normal View History

2023-08-17 20:53:13 +02:00
package com.minelittlepony.unicopia.entity;
import java.util.Optional;
2023-08-25 23:06:08 +02:00
import java.util.function.Predicate;
import java.util.stream.Stream;
2023-08-17 20:53:13 +02:00
import org.jetbrains.annotations.Nullable;
2023-08-25 23:06:08 +02:00
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.advancement.UCriteria;
2023-08-25 23:06:08 +02:00
import com.minelittlepony.unicopia.entity.ai.ArenaAttackGoal;
import com.minelittlepony.unicopia.entity.player.Pony;
2023-08-17 20:53:13 +02:00
import com.minelittlepony.unicopia.item.AmuletItem;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
2023-08-25 23:06:08 +02:00
import com.minelittlepony.unicopia.particle.ParticleSource;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
2023-08-17 20:53:13 +02:00
import com.minelittlepony.unicopia.util.VecHelper;
2023-08-25 23:06:08 +02:00
import com.minelittlepony.unicopia.util.shape.Sphere;
2023-08-17 20:53:13 +02:00
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.ExperienceOrbEntity;
import net.minecraft.entity.ItemEntity;
2023-08-17 20:53:13 +02:00
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.MovementType;
2023-08-17 20:53:13 +02:00
import net.minecraft.entity.ai.goal.ActiveTargetGoal;
2023-08-25 23:06:08 +02:00
import net.minecraft.entity.ai.goal.FlyGoal;
import net.minecraft.entity.ai.goal.LongDoorInteractGoal;
2023-08-17 20:53:13 +02:00
import net.minecraft.entity.ai.goal.LookAroundGoal;
import net.minecraft.entity.ai.goal.LookAtEntityGoal;
import net.minecraft.entity.ai.goal.PounceAtTargetGoal;
import net.minecraft.entity.ai.goal.RevengeGoal;
import net.minecraft.entity.ai.goal.WanderAroundGoal;
2023-08-25 23:06:08 +02:00
import net.minecraft.entity.ai.pathing.BirdPathNodeMaker;
2023-08-17 20:53:13 +02:00
import net.minecraft.entity.ai.pathing.EntityNavigation;
import net.minecraft.entity.ai.pathing.MobNavigation;
2023-08-25 23:06:08 +02:00
import net.minecraft.entity.ai.pathing.PathNodeNavigator;
import net.minecraft.entity.ai.pathing.PathNodeType;
2023-08-17 20:53:13 +02:00
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.boss.BossBar;
import net.minecraft.entity.boss.ServerBossBar;
import net.minecraft.entity.boss.BossBar.Style;
2023-08-17 20:53:13 +02:00
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.passive.IronGolemEntity;
import net.minecraft.entity.passive.MerchantEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtHelper;
2023-08-25 23:06:08 +02:00
import net.minecraft.particle.ParticleEffect;
2023-08-17 20:53:13 +02:00
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.registry.tag.*;
import net.minecraft.server.network.ServerPlayerEntity;
2023-08-25 23:06:08 +02:00
import net.minecraft.server.world.ServerWorld;
2023-08-17 20:53:13 +02:00
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
2023-08-25 23:06:08 +02:00
import net.minecraft.util.math.MathHelper;
2023-08-17 20:53:13 +02:00
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
2023-08-17 20:53:13 +02:00
import net.minecraft.world.World;
import net.minecraft.world.WorldEvents;
import net.minecraft.world.Heightmap.Type;
2023-08-17 20:53:13 +02:00
import net.minecraft.world.event.GameEvent;
2023-08-25 23:06:08 +02:00
public class SombraEntity extends HostileEntity implements ArenaCombatant, ParticleSource<SombraEntity> {
static final byte BITE = 70;
static final int MAX_BITE_TIME = 20;
static final Predicate<Entity> EFFECT_TARGET_PREDICATE = EntityPredicates.VALID_LIVING_ENTITY.and(EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR);
2023-08-17 20:53:13 +02:00
private static final TrackedData<Optional<BlockPos>> HOME_POS = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS);
private static final TrackedData<Float> TARGET_SIZE = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.FLOAT);
2023-08-17 20:53:13 +02:00
private final ServerBossBar bossBar;
2023-08-25 23:06:08 +02:00
final EntityReference<StormCloudEntity> stormCloud = new EntityReference<>();
private int prevBiteTime;
private int biteTime;
private float prevSize;
private float currentSize;
2023-08-25 23:06:08 +02:00
public static void startEncounter(World world, BlockPos pos) {
StormCloudEntity cloud = UEntities.STORM_CLOUD.create(world);
cloud.setPosition(pos.up(10).toCenterPos());
cloud.setSize(1);
cloud.cursed = true;
world.spawnEntity(cloud);
}
2023-08-17 20:53:13 +02:00
public SombraEntity(EntityType<SombraEntity> type, World world) {
this(type, world, null);
}
public SombraEntity(EntityType<SombraEntity> type, World world, @Nullable ServerBossBar bossBar) {
2023-08-17 20:53:13 +02:00
super(type, world);
this.bossBar = bossBar == null ? createBossBar(getDisplayName()) : bossBar;
this.bossBar.setName(getDisplayName());
this.bossBar.setStyle(Style.NOTCHED_10);
}
public static ServerBossBar createBossBar(Text name) {
return new SombraBossBar(name);
2023-08-17 20:53:13 +02:00
}
public static DefaultAttributeContainer.Builder createMobAttributes() {
return HostileEntity.createMobAttributes()
.add(EntityAttributes.GENERIC_MAX_HEALTH, 2000)
2023-08-25 23:06:08 +02:00
.add(EntityAttributes.GENERIC_ATTACK_KNOCKBACK, 1.5)
.add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 22);
}
@Override
public SombraEntity asEntity() {
return this;
2023-08-17 20:53:13 +02:00
}
@Override
protected Entity.MoveEffect getMoveEffect() {
return Entity.MoveEffect.NONE;
}
@Override
public boolean canAvoidTraps() {
return true;
}
@Override
protected SoundEvent getHurtSound(DamageSource source) {
return SoundEvents.ENTITY_WARDEN_HURT;
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.ENTITY_WARDEN_DEATH;
}
@Override
protected void initDataTracker() {
super.initDataTracker();
dataTracker.startTracking(HOME_POS, Optional.empty());
dataTracker.startTracking(TARGET_SIZE, 1F);
2023-08-17 20:53:13 +02:00
}
@Override
protected void initGoals() {
2023-08-25 23:06:08 +02:00
goalSelector.add(2, new LongDoorInteractGoal(this, true));
goalSelector.add(5, new FlyGoal(this, 1));
goalSelector.add(6, new LookAtEntityGoal(this, PlayerEntity.class, 18F));
2023-08-17 20:53:13 +02:00
goalSelector.add(7, new LookAroundGoal(this));
2023-08-25 23:06:08 +02:00
goalSelector.add(7, new WanderAroundGoal(this, 1));
goalSelector.add(8, new PounceAtTargetGoal(this, 1.3F));
goalSelector.add(8, new ArenaAttackGoal<>(this));
2023-08-17 20:53:13 +02:00
targetSelector.add(1, new RevengeGoal(this));
targetSelector.add(2, new ActiveTargetGoal<>(this, PlayerEntity.class, false));
targetSelector.add(3, new ActiveTargetGoal<>(this, MerchantEntity.class, false));
targetSelector.add(3, new ActiveTargetGoal<>(this, IronGolemEntity.class, true));
}
@Override
protected EntityNavigation createNavigation(World world) {
2023-08-25 23:06:08 +02:00
MobNavigation nav = new MobNavigation(this, world) {
@Override
protected PathNodeNavigator createPathNodeNavigator(int range) {
nodeMaker = new BirdPathNodeMaker();
nodeMaker.setCanEnterOpenDoors(true);
return new PathNodeNavigator(nodeMaker, range);
}
};
2023-08-17 20:53:13 +02:00
nav.setCanPathThroughDoors(true);
nav.setCanSwim(true);
nav.setCanEnterOpenDoors(true);
2023-08-25 23:06:08 +02:00
nav.canJumpToNext(PathNodeType.UNPASSABLE_RAIL);
2023-08-17 20:53:13 +02:00
return nav;
}
2023-08-25 23:06:08 +02:00
@Override
2023-08-17 20:53:13 +02:00
public Optional<BlockPos> getHomePos() {
return dataTracker.get(HOME_POS);
}
public void setHomePos(BlockPos pos) {
dataTracker.set(HOME_POS, Optional.of(pos));
}
2023-08-25 23:06:08 +02:00
public float getBiteAmount(float tickDelta) {
float progress = (MathHelper.lerp(tickDelta, prevBiteTime, biteTime) / (float)MAX_BITE_TIME);
return 1 - Math.abs(MathHelper.sin(progress * MathHelper.PI * 3));
}
@Override
public float getScaleFactor() {
return Math.max(1, dataTracker.get(TARGET_SIZE));
}
public float getScaleFactor(float tickDelta) {
return MathHelper.lerp(tickDelta, prevSize, currentSize);
}
public void setScaleFactor(float targetSize) {
dataTracker.set(TARGET_SIZE, targetSize);
calculateDimensions();
2023-08-25 23:06:08 +02:00
}
2023-08-17 20:53:13 +02:00
@Override
public void tick() {
2023-08-25 23:06:08 +02:00
setPersistent();
2023-08-17 20:53:13 +02:00
Optional<BlockPos> homePos = getHomePos();
if (homePos.isEmpty() && !isRemoved()) {
setHomePos(getWorld().getTopPosition(Type.MOTION_BLOCKING_NO_LEAVES, getBlockPos()));
homePos = getHomePos();
2023-08-17 20:53:13 +02:00
}
2023-08-25 23:06:08 +02:00
if (getBlockPos().getSquaredDistance(homePos.get()) > MathHelper.square(getAreaRadius())) {
2023-08-17 20:53:13 +02:00
teleportTo(Vec3d.ofCenter(homePos.get()));
2023-08-25 23:06:08 +02:00
getNavigation().stop();
}
prevBiteTime = biteTime;
if (biteTime > 0) {
biteTime--;
2023-08-17 20:53:13 +02:00
}
float targetSize = getScaleFactor();
boolean sizeChanging = prevSize != currentSize;
prevSize = currentSize;
tickGrowth(targetSize, sizeChanging);
if (!hasPositionTarget() && homePos.isPresent()) {
setPositionTarget(homePos.get(), (int)getAreaRadius());
}
2023-08-17 20:53:13 +02:00
super.tick();
if (getTarget() == null && getVelocity().y < -0.1F) {
2023-08-25 23:06:08 +02:00
setVelocity(getVelocity().multiply(1, 0.4, 1));
}
2023-08-25 23:06:08 +02:00
addVelocity(0, 0.0242F, 0);
if (isDead()) {
return;
}
2023-08-17 20:53:13 +02:00
if (isSubmergedInWater()) {
jump();
}
2023-08-25 23:06:08 +02:00
if (random.nextInt(1200) == 0) {
laugh();
2023-08-17 20:53:13 +02:00
}
2023-08-25 23:06:08 +02:00
if (random.nextInt(340) == 0) {
2023-08-17 20:53:13 +02:00
playSound(SoundEvents.AMBIENT_CAVE.value(), 1, 0.3F);
2023-08-25 23:06:08 +02:00
} else if (random.nextInt(1340) == 0) {
playSound(USounds.ENTITY_SOMBRA_AMBIENT, 1, 1);
2023-08-17 20:53:13 +02:00
}
if (getWorld().isClient) {
2023-08-25 23:06:08 +02:00
generateBodyParticles();
} else {
for (BlockPos p : BlockPos.iterateOutwards(getBlockPos(), 2, 1, 2)) {
if (getWorld().getBlockState(p).getLuminance() > 13) {
2023-08-25 23:06:08 +02:00
destroyLightSource(p);
}
}
if (random.nextInt(150) == 0) {
for (BlockPos p : BlockPos.iterateRandomly(random, 3, getBlockPos(), 20)) {
CrystalShardsEntity.infestBlock((ServerWorld)getWorld(), p);
}
2023-08-17 20:53:13 +02:00
}
2023-08-25 23:06:08 +02:00
if (getTarget() == null && getNavigation().isIdle()) {
getNavigation().startMovingTo(homePos.get().getX(), homePos.get().getY() + 5, homePos.get().getZ(), 2);
2023-08-17 20:53:13 +02:00
}
}
if (getHealth() < getMaxHealth()) {
for (Entity shard : getWorld().getEntitiesByClass(CrystalShardsEntity.class, getBoundingBox().expand(50), EntityPredicates.VALID_ENTITY)) {
if (age % 150 == 0) {
heal(2);
}
ParticleUtils.spawnParticle(getWorld(),
new FollowingParticleEffect(UParticles.HEALTH_DRAIN, this, 0.2F)
.withChild(ParticleTypes.CAMPFIRE_SIGNAL_SMOKE),
shard.getPos(),
Vec3d.ZERO
);
}
}
2023-08-25 23:06:08 +02:00
getHomePos().ifPresent(this::generateArenaEffects);
2023-08-17 20:53:13 +02:00
}
protected void tickGrowth(float targetSize, boolean changing) {
if (currentSize != targetSize) {
float sizeDifference = (dataTracker.get(TARGET_SIZE) - currentSize);
currentSize = Math.abs(sizeDifference) < 0.01F ? targetSize : currentSize + (sizeDifference * 0.2F);
calculateDimensions();
}
if (currentSize == targetSize && changing) {
laugh();
}
if (currentSize == targetSize && isDead()) {
setScaleFactor(currentSize + 1);
}
}
private void laugh() {
if (!getWorld().isClient) {
playSound(USounds.ENTITY_SOMBRA_LAUGH, 1, 1);
getWorld().sendEntityStatus(this, BITE);
}
}
2023-08-25 23:06:08 +02:00
protected void applyAreaEffects(Entity target) {
if (this.age % 150 == 0) {
target.playSound(
random.nextInt(30) == 0 ? USounds.ENTITY_SOMBRA_AMBIENT
: random.nextInt(10) == 0 ? USounds.Vanilla.ENTITY_GHAST_AMBIENT
: USounds.Vanilla.AMBIENT_CAVE.value(),
(float)random.nextTriangular(1, 0.2F),
(float)random.nextTriangular(0.3F, 0.2F)
);
}
if (this.age % 1000 < 50) {
((LivingEntity)target).addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, 26, 0, true, false));
((LivingEntity)target).addStatusEffect(new StatusEffectInstance(StatusEffects.DARKNESS, 26, 0, true, false));
}
2023-08-25 23:06:08 +02:00
if (getTarget() == null && target instanceof PlayerEntity player && player.distanceTo(this) < getAreaRadius() / 2F) {
setTarget(player);
if (teleportTo(target.getPos())) {
setPosition(getPos().add(0, 4, 0));
}
}
2023-08-17 20:53:13 +02:00
}
2023-08-25 23:06:08 +02:00
protected void destroyLightSource(BlockPos pos) {
getWorld().breakBlock(pos, true);
playSound(USounds.ENTITY_SOMBRA_SNICKER, 1, 1);
2023-08-17 20:53:13 +02:00
}
2023-08-25 23:06:08 +02:00
protected void generateBodyParticles() {
for (int i = 0; i < 3; i++) {
2023-08-25 23:06:08 +02:00
getWorld().addParticle(ParticleTypes.LARGE_SMOKE,
random.nextTriangular(getX(), 8),
random.nextTriangular(getY(), 1),
random.nextTriangular(getZ(), 8),
0,
0,
0
);
}
2023-08-17 20:53:13 +02:00
}
2023-08-25 23:06:08 +02:00
private void generateArenaEffects(BlockPos home) {
if (getWorld().isClient()) {
Stream.concat(
new Sphere(false, getAreaRadius()).translate(home).randomPoints(random).filter(this::isSurfaceBlock).limit(80),
new Sphere(true, getAreaRadius()).translate(home).randomPoints(random).filter(this::isSurfaceBlock).limit(30))
.forEach(pos -> {
ParticleEffect type = random.nextInt(3) < 1 ? ParticleTypes.LARGE_SMOKE : ParticleTypes.SOUL_FIRE_FLAME;
ParticleUtils.spawnParticle(getWorld(), type, pos, Vec3d.ZERO);
ParticleUtils.spawnParticle(getWorld(), type, pos, pos.subtract(getPos()).add(0, 0.1, 0).multiply(-0.013));
});
} else {
for (Entity target : VecHelper.findInRange(this, getWorld(), home.toCenterPos(), getAreaRadius() - 0.2F, EFFECT_TARGET_PREDICATE)) {
applyAreaEffects(target);
}
}
}
2023-08-17 20:53:13 +02:00
2023-08-25 23:06:08 +02:00
private boolean isSurfaceBlock(Vec3d pos) {
BlockPos bPos = BlockPos.ofFloored(pos);
return getWorld().isAir(bPos) && !getWorld().isAir(bPos.down());
2023-08-17 20:53:13 +02:00
}
@Override
2023-08-25 23:06:08 +02:00
protected void mobTick() {
super.mobTick();
bossBar.setPercent(getHealth() / getMaxHealth());
}
2023-08-17 20:53:13 +02:00
2023-08-25 23:06:08 +02:00
@Override
public boolean shouldRender(double distance) {
double d = 64 * getRenderDistanceMultiplier();
return distance < d * d;
2023-08-17 20:53:13 +02:00
}
@Override
public boolean handleFallDamage(float distance, float damageMultiplier, DamageSource cause) {
return false;
}
@Override
public boolean damage(DamageSource source, float amount) {
if (source.getAttacker() instanceof PlayerEntity player) {
if (AmuletSelectors.ALICORN_AMULET.test(player)) {
if (!getWorld().isClient) {
2023-08-25 23:06:08 +02:00
playSound(USounds.ENTITY_SOMBRA_SNICKER, 1, 1);
2023-08-17 20:53:13 +02:00
player.sendMessage(Text.translatable("entity.unicopia.sombra.taunt"));
}
}
ItemStack amulet = AmuletItem.getForEntity(player);
if (amulet.isOf(UItems.ALICORN_AMULET)) {
amulet.decrement(1);
}
}
boolean damaged = super.damage(source, amount);
if (!getWorld().isClient) {
if (source.getAttacker() instanceof PlayerEntity player) {
teleportRandomly(16);
}
float targetSize = getScaleFactor();
if (targetSize > 1) {
setScaleFactor(Math.max(1, targetSize * 0.9F));
}
2023-08-17 20:53:13 +02:00
}
return damaged;
}
2023-08-25 23:06:08 +02:00
@Override
public void onDeath(DamageSource damageSource) {
if (!dead) {
stormCloud.ifPresent(getWorld(), cloud -> {
cloud.setStormTicks(0);
cloud.setDissipating(true);
});
stormCloud.set(null);
getHomePos().ifPresent(home -> {
VecHelper.findInRange(this, getWorld(), home.toCenterPos(), getAreaRadius() - 0.2F, e -> e instanceof CrystalShardsEntity).forEach(e -> {
((CrystalShardsEntity)e).setDecaying(true);
});
for (Entity e : VecHelper.findInRange(this, getWorld(), home.toCenterPos(), getAreaRadius() - 0.2F, EFFECT_TARGET_PREDICATE)) {
Pony.of(e).ifPresent(pony -> {
pony.getCorruption().set(0);
UCriteria.DEFEAT_SOMBRA.trigger(e);
});
}
2023-08-25 23:06:08 +02:00
});
2023-08-25 23:06:08 +02:00
}
super.onDeath(damageSource);
}
@Override
protected void dropEquipment(DamageSource source, int lootingMultiplier, boolean allowDrops) {
super.dropEquipment(source, lootingMultiplier, allowDrops);
ItemEntity itemEntity = dropItem(UItems.BROKEN_ALICORN_AMULET);
if (itemEntity != null) {
itemEntity.setCovetedItem();
}
}
@Override
protected void updatePostDeath() {
if (++deathTime >= 180 && deathTime <= 200) {
getWorld().addParticle(ParticleTypes.EXPLOSION_EMITTER,
random.nextTriangular(getX(), 4F),
random.nextTriangular(getY() + 2, 2F),
random.nextTriangular(getZ(), 4F), 0, 0, 0);
}
move(MovementType.SELF, new Vec3d(0, 0.3F, 0));
if (getWorld() instanceof ServerWorld sw) {
final boolean dropLoot = this.getWorld().getGameRules().getBoolean(GameRules.DO_MOB_LOOT);
final int experience = 500;
if (deathTime > 150 && deathTime % 5 == 0 && dropLoot) {
ExperienceOrbEntity.spawn(sw, getPos(), MathHelper.floor(experience * 0.08f));
}
if (deathTime == 1 && !isSilent()) {
getWorld().syncGlobalEvent(WorldEvents.ENDER_DRAGON_DIES, this.getBlockPos(), 0);
}
if (deathTime == 200) {
if (dropLoot) {
ExperienceOrbEntity.spawn(sw, getPos(), MathHelper.floor(experience * 0.2f));
}
remove(RemovalReason.KILLED);
emitGameEvent(GameEvent.ENTITY_DIE);
}
}
}
2023-08-17 20:53:13 +02:00
@Override
protected void fall(double y, boolean onGroundIn, BlockState state, BlockPos pos) {
}
2023-08-25 23:06:08 +02:00
@Override
public boolean canTarget(LivingEntity target) {
return super.canTarget(target) && getHomePos().filter(home -> target.getPos().isInRange(home.toCenterPos(), getAreaRadius())).isPresent();
}
@Override
public boolean isInWalkTargetRange(BlockPos pos) {
BlockPos center = getHomePos().orElse(getBlockPos());
double distance = pos.getSquaredDistanceFromCenter(center.getX() + 0.5, center.getY() + 0.5, center.getZ() + 0.5);
return distance < MathHelper.square(getAreaRadius());
}
2023-08-25 23:06:08 +02:00
@Override
public boolean tryAttack(Entity target) {
laugh();
2023-08-25 23:06:08 +02:00
return super.tryAttack(target);
}
@Override
public void handleStatus(byte status) {
if (status == BITE) {
biteTime = MAX_BITE_TIME;
} else {
super.handleStatus(status);
}
}
2023-08-17 20:53:13 +02:00
protected boolean teleportRandomly(int maxDistance) {
if (getWorld().isClient() || !isAlive()) {
return false;
}
return teleportTo(getPos().add(VecHelper.supply(() -> random.nextTriangular(0, maxDistance))));
}
2023-08-25 23:06:08 +02:00
@Override
public boolean teleportTo(Vec3d destination) {
2023-08-17 20:53:13 +02:00
Vec3d oldPos = getPos();
if (canTeleportTo(destination) && teleport(destination.x, destination.y, destination.z, true)) {
getWorld().emitGameEvent(GameEvent.TELEPORT, oldPos, GameEvent.Emitter.of(this));
return true;
}
return false;
}
@SuppressWarnings("deprecation")
private boolean canTeleportTo(Vec3d destination) {
BlockPos.Mutable mutable = new BlockPos.Mutable(destination.x, destination.y, destination.z);
while (mutable.getY() > getWorld().getBottomY() && !getWorld().getBlockState(mutable).blocksMovement()) {
mutable.move(Direction.DOWN);
}
BlockState destinationState = getWorld().getBlockState(mutable);
return destinationState.blocksMovement() && !destinationState.getFluidState().isIn(FluidTags.WATER);
}
@Override
@Deprecated
public float getBrightnessAtEyes() {
return super.getBrightnessAtEyes() * 0.2F;
}
@Override
public void setCustomName(@Nullable Text name) {
super.setCustomName(name);
bossBar.setName(getDisplayName());
}
@Override
public void onStartedTrackingBy(ServerPlayerEntity player) {
super.onStartedTrackingBy(player);
bossBar.addPlayer(player);
}
@Override
public void onStoppedTrackingBy(ServerPlayerEntity player) {
super.onStoppedTrackingBy(player);
bossBar.removePlayer(player);
}
@Override
public void writeCustomDataToNbt(NbtCompound nbt) {
super.writeCustomDataToNbt(nbt);
getHomePos().map(NbtHelper::fromBlockPos).ifPresent(pos -> {
nbt.put("homePos", pos);
});
2023-08-25 23:06:08 +02:00
nbt.put("cloud", stormCloud.toNBT());
nbt.putFloat("size", getScaleFactor());
2023-08-17 20:53:13 +02:00
}
@Override
public void readCustomDataFromNbt(NbtCompound nbt) {
super.readCustomDataFromNbt(nbt);
if (nbt.contains("homePos", NbtElement.COMPOUND_TYPE)) {
setHomePos(NbtHelper.toBlockPos(nbt.getCompound("homePos")));
}
if (hasCustomName()) {
bossBar.setName(getDisplayName());
}
setScaleFactor(nbt.getFloat("size"));
2023-08-25 23:06:08 +02:00
stormCloud.fromNBT(nbt.getCompound("cloud"));
2023-08-17 20:53:13 +02:00
}
private static class SombraBossBar extends ServerBossBar {
public SombraBossBar(Text displayName) {
super(displayName, BossBar.Color.PURPLE, BossBar.Style.PROGRESS);
setDarkenSky(true);
setThickenFog(true);
setDragonMusic(true);
}
@Override
public void setPercent(float percent) {
super.setPercent(percent);
if (percent > 0.6F && getColor() == Color.PURPLE) {
setColor(Color.RED);
}
}
}
2023-08-17 20:53:13 +02:00
}