Newer
Older
void-pack-super-server / work / nms.old.1585251758016 / minecraft / server / EntityWither.java
package net.minecraft.server;

import com.google.common.collect.ImmutableList;
import java.util.EnumSet;
import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable;

// CraftBukkit start
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
// CraftBukkit end

public class EntityWither extends EntityMonster implements IRangedEntity {

    private static final DataWatcherObject<Integer> b = DataWatcher.a(EntityWither.class, DataWatcherRegistry.b);
    private static final DataWatcherObject<Integer> c = DataWatcher.a(EntityWither.class, DataWatcherRegistry.b);
    private static final DataWatcherObject<Integer> d = DataWatcher.a(EntityWither.class, DataWatcherRegistry.b);
    private static final List<DataWatcherObject<Integer>> bw = ImmutableList.of(EntityWither.b, EntityWither.c, EntityWither.d);
    private static final DataWatcherObject<Integer> bx = DataWatcher.a(EntityWither.class, DataWatcherRegistry.b);
    private final float[] by = new float[2];
    private final float[] bz = new float[2];
    private final float[] bA = new float[2];
    private final float[] bB = new float[2];
    private final int[] bC = new int[2];
    private final int[] bD = new int[2];
    private int bE;
    public final BossBattleServer bossBattle;
    private static final Predicate<EntityLiving> bG = (entityliving) -> {
        return entityliving.getMonsterType() != EnumMonsterType.UNDEAD && entityliving.dN();
    };
    private static final PathfinderTargetCondition bH = (new PathfinderTargetCondition()).a(20.0D).a(EntityWither.bG);

    public EntityWither(EntityTypes<? extends EntityWither> entitytypes, World world) {
        super(entitytypes, world);
        this.bossBattle = (BossBattleServer) (new BossBattleServer(this.getScoreboardDisplayName(), BossBattle.BarColor.PURPLE, BossBattle.BarStyle.PROGRESS)).setDarkenSky(true);
        this.setHealth(this.getMaxHealth());
        this.getNavigation().d(true);
        this.f = 50;
    }

    @Override
    protected void initPathfinder() {
        this.goalSelector.a(0, new EntityWither.a());
        this.goalSelector.a(2, new PathfinderGoalArrowAttack(this, 1.0D, 40, 20.0F));
        this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 1.0D));
        this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F));
        this.goalSelector.a(7, new PathfinderGoalRandomLookaround(this));
        this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, new Class[0]));
        this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityInsentient.class, 0, false, false, EntityWither.bG));
    }

    @Override
    protected void initDatawatcher() {
        super.initDatawatcher();
        this.datawatcher.register(EntityWither.b, 0);
        this.datawatcher.register(EntityWither.c, 0);
        this.datawatcher.register(EntityWither.d, 0);
        this.datawatcher.register(EntityWither.bx, 0);
    }

    @Override
    public void b(NBTTagCompound nbttagcompound) {
        super.b(nbttagcompound);
        nbttagcompound.setInt("Invul", this.eq());
    }

    @Override
    public void a(NBTTagCompound nbttagcompound) {
        super.a(nbttagcompound);
        this.s(nbttagcompound.getInt("Invul"));
        if (this.hasCustomName()) {
            this.bossBattle.a(this.getScoreboardDisplayName());
        }

    }

    @Override
    public void setCustomName(@Nullable IChatBaseComponent ichatbasecomponent) {
        super.setCustomName(ichatbasecomponent);
        this.bossBattle.a(this.getScoreboardDisplayName());
    }

    @Override
    protected SoundEffect getSoundAmbient() {
        return SoundEffects.ENTITY_WITHER_AMBIENT;
    }

    @Override
    protected SoundEffect getSoundHurt(DamageSource damagesource) {
        return SoundEffects.ENTITY_WITHER_HURT;
    }

    @Override
    protected SoundEffect getSoundDeath() {
        return SoundEffects.ENTITY_WITHER_DEATH;
    }

    @Override
    public void movementTick() {
        Vec3D vec3d = this.getMot().d(1.0D, 0.6D, 1.0D);

        if (!this.world.isClientSide && this.getHeadTarget(0) > 0) {
            Entity entity = this.world.getEntity(this.getHeadTarget(0));

            if (entity != null) {
                double d0 = vec3d.y;

                if (this.locY() < entity.locY() || !this.J_() && this.locY() < entity.locY() + 5.0D) {
                    d0 = Math.max(0.0D, d0);
                    d0 += 0.3D - d0 * 0.6000000238418579D;
                }

                vec3d = new Vec3D(vec3d.x, d0, vec3d.z);
                Vec3D vec3d1 = new Vec3D(entity.locX() - this.locX(), 0.0D, entity.locZ() - this.locZ());

                if (b(vec3d1) > 9.0D) {
                    Vec3D vec3d2 = vec3d1.d();

                    vec3d = vec3d.add(vec3d2.x * 0.3D - vec3d.x * 0.6D, 0.0D, vec3d2.z * 0.3D - vec3d.z * 0.6D);
                }
            }
        }

        this.setMot(vec3d);
        if (b(vec3d) > 0.05D) {
            this.yaw = (float) MathHelper.d(vec3d.z, vec3d.x) * 57.295776F - 90.0F;
        }

        super.movementTick();

        int i;

        for (i = 0; i < 2; ++i) {
            this.bB[i] = this.bz[i];
            this.bA[i] = this.by[i];
        }

        int j;

        for (i = 0; i < 2; ++i) {
            j = this.getHeadTarget(i + 1);
            Entity entity1 = null;

            if (j > 0) {
                entity1 = this.world.getEntity(j);
            }

            if (entity1 != null) {
                double d1 = this.u(i + 1);
                double d2 = this.v(i + 1);
                double d3 = this.w(i + 1);
                double d4 = entity1.locX() - d1;
                double d5 = entity1.getHeadY() - d2;
                double d6 = entity1.locZ() - d3;
                double d7 = (double) MathHelper.sqrt(d4 * d4 + d6 * d6);
                float f = (float) (MathHelper.d(d6, d4) * 57.2957763671875D) - 90.0F;
                float f1 = (float) (-(MathHelper.d(d5, d7) * 57.2957763671875D));

                this.by[i] = this.a(this.by[i], f1, 40.0F);
                this.bz[i] = this.a(this.bz[i], f, 10.0F);
            } else {
                this.bz[i] = this.a(this.bz[i], this.aI, 10.0F);
            }
        }

        boolean flag = this.J_();

        for (j = 0; j < 3; ++j) {
            double d8 = this.u(j);
            double d9 = this.v(j);
            double d10 = this.w(j);

            this.world.addParticle(Particles.SMOKE, d8 + this.random.nextGaussian() * 0.30000001192092896D, d9 + this.random.nextGaussian() * 0.30000001192092896D, d10 + this.random.nextGaussian() * 0.30000001192092896D, 0.0D, 0.0D, 0.0D);
            if (flag && this.world.random.nextInt(4) == 0) {
                this.world.addParticle(Particles.ENTITY_EFFECT, d8 + this.random.nextGaussian() * 0.30000001192092896D, d9 + this.random.nextGaussian() * 0.30000001192092896D, d10 + this.random.nextGaussian() * 0.30000001192092896D, 0.699999988079071D, 0.699999988079071D, 0.5D);
            }
        }

        if (this.eq() > 0) {
            for (j = 0; j < 3; ++j) {
                this.world.addParticle(Particles.ENTITY_EFFECT, this.locX() + this.random.nextGaussian(), this.locY() + (double) (this.random.nextFloat() * 3.3F), this.locZ() + this.random.nextGaussian(), 0.699999988079071D, 0.699999988079071D, 0.8999999761581421D);
            }
        }

    }

    @Override
    protected void mobTick() {
        int i;

        if (this.eq() > 0) {
            i = this.eq() - 1;
            if (i <= 0) {
                Explosion.Effect explosion_effect = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? Explosion.Effect.DESTROY : Explosion.Effect.NONE;
                // CraftBukkit start
                // this.world.createExplosion(this, this.locX(), this.getHeadY(), this.locZ(), 7.0F, false, explosion_effect);
                ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false);
                this.world.getServer().getPluginManager().callEvent(event);

                if (!event.isCancelled()) {
                    this.world.createExplosion(this, this.locX(), this.getHeadY(), this.locZ(), event.getRadius(), event.getFire(), explosion_effect);
                }
                // CraftBukkit end

                // CraftBukkit start - Use relative location for far away sounds
                // this.world.b(1023, new BlockPosition(this), 0);
                int viewDistance = ((WorldServer) this.world).getServer().getViewDistance() * 16;
                for (EntityPlayer player : (List<EntityPlayer>) MinecraftServer.getServer().getPlayerList().players) {
                    double deltaX = this.locX() - player.locX();
                    double deltaZ = this.locZ() - player.locZ();
                    double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
                    if (distanceSquared > viewDistance * viewDistance) {
                        double deltaLength = Math.sqrt(distanceSquared);
                        double relativeX = player.locX() + (deltaX / deltaLength) * viewDistance;
                        double relativeZ = player.locZ() + (deltaZ / deltaLength) * viewDistance;
                        player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1023, new BlockPosition((int) relativeX, (int) this.locY(), (int) relativeZ), 0, true));
                    } else {
                        player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1023, new BlockPosition((int) this.locX(), (int) this.locY(), (int) this.locZ()), 0, true));
                    }
                }
                // CraftBukkit end
            }

            this.s(i);
            if (this.ticksLived % 10 == 0) {
                this.heal(10.0F, EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit
            }

        } else {
            super.mobTick();

            int j;

            for (i = 1; i < 3; ++i) {
                if (this.ticksLived >= this.bC[i - 1]) {
                    this.bC[i - 1] = this.ticksLived + 10 + this.random.nextInt(10);
                    if (this.world.getDifficulty() == EnumDifficulty.NORMAL || this.world.getDifficulty() == EnumDifficulty.HARD) {
                        int k = i - 1;
                        int l = this.bD[i - 1];

                        this.bD[k] = this.bD[i - 1] + 1;
                        if (l > 15) {
                            float f = 10.0F;
                            float f1 = 5.0F;
                            double d0 = MathHelper.a(this.random, this.locX() - 10.0D, this.locX() + 10.0D);
                            double d1 = MathHelper.a(this.random, this.locY() - 5.0D, this.locY() + 5.0D);
                            double d2 = MathHelper.a(this.random, this.locZ() - 10.0D, this.locZ() + 10.0D);

                            this.a(i + 1, d0, d1, d2, true);
                            this.bD[i - 1] = 0;
                        }
                    }

                    j = this.getHeadTarget(i);
                    if (j > 0) {
                        Entity entity = this.world.getEntity(j);

                        if (entity != null && entity.isAlive() && this.h(entity) <= 900.0D && this.hasLineOfSight(entity)) {
                            if (entity instanceof EntityHuman && ((EntityHuman) entity).abilities.isInvulnerable) {
                                this.setHeadTarget(i, 0);
                            } else {
                                this.a(i + 1, (EntityLiving) entity);
                                this.bC[i - 1] = this.ticksLived + 40 + this.random.nextInt(20);
                                this.bD[i - 1] = 0;
                            }
                        } else {
                            this.setHeadTarget(i, 0);
                        }
                    } else {
                        List<EntityLiving> list = this.world.a(EntityLiving.class, EntityWither.bH, this, this.getBoundingBox().grow(20.0D, 8.0D, 20.0D));

                        for (int i1 = 0; i1 < 10 && !list.isEmpty(); ++i1) {
                            EntityLiving entityliving = (EntityLiving) list.get(this.random.nextInt(list.size()));

                            if (entityliving != this && entityliving.isAlive() && this.hasLineOfSight(entityliving)) {
                                if (entityliving instanceof EntityHuman) {
                                    if (!((EntityHuman) entityliving).abilities.isInvulnerable) {
                                        if (CraftEventFactory.callEntityTargetLivingEvent(this, entityliving, EntityTargetEvent.TargetReason.CLOSEST_PLAYER).isCancelled()) continue; // CraftBukkit
                                        this.setHeadTarget(i, entityliving.getId());
                                    }
                                } else {
                                    if (CraftEventFactory.callEntityTargetLivingEvent(this, entityliving, EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) continue; // CraftBukkit
                                    this.setHeadTarget(i, entityliving.getId());
                                }
                                break;
                            }

                            list.remove(entityliving);
                        }
                    }
                }
            }

            if (this.getGoalTarget() != null) {
                this.setHeadTarget(0, this.getGoalTarget().getId());
            } else {
                this.setHeadTarget(0, 0);
            }

            if (this.bE > 0) {
                --this.bE;
                if (this.bE == 0 && this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) {
                    i = MathHelper.floor(this.locY());
                    j = MathHelper.floor(this.locX());
                    int j1 = MathHelper.floor(this.locZ());
                    boolean flag = false;

                    for (int k1 = -1; k1 <= 1; ++k1) {
                        for (int l1 = -1; l1 <= 1; ++l1) {
                            for (int i2 = 0; i2 <= 3; ++i2) {
                                int j2 = j + k1;
                                int k2 = i + i2;
                                int l2 = j1 + l1;
                                BlockPosition blockposition = new BlockPosition(j2, k2, l2);
                                IBlockData iblockdata = this.world.getType(blockposition);

                                if (b(iblockdata)) {
                                    // CraftBukkit start
                                    if (CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, Blocks.AIR.getBlockData()).isCancelled()) {
                                        continue;
                                    }
                                    // CraftBukkit end
                                    flag = this.world.a(blockposition, true, this) || flag;
                                }
                            }
                        }
                    }

                    if (flag) {
                        this.world.a((EntityHuman) null, 1022, new BlockPosition(this), 0);
                    }
                }
            }

            if (this.ticksLived % 20 == 0) {
                this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit
            }

            this.bossBattle.setProgress(this.getHealth() / this.getMaxHealth());
        }
    }

    public static boolean b(IBlockData iblockdata) {
        return !iblockdata.isAir() && !TagsBlock.WITHER_IMMUNE.isTagged(iblockdata.getBlock());
    }

    public void l() {
        this.s(220);
        this.setHealth(this.getMaxHealth() / 3.0F);
    }

    @Override
    public void a(IBlockData iblockdata, Vec3D vec3d) {}

    @Override
    public void b(EntityPlayer entityplayer) {
        super.b(entityplayer);
        this.bossBattle.addPlayer(entityplayer);
    }

    @Override
    public void c(EntityPlayer entityplayer) {
        super.c(entityplayer);
        this.bossBattle.removePlayer(entityplayer);
    }

    private double u(int i) {
        if (i <= 0) {
            return this.locX();
        } else {
            float f = (this.aI + (float) (180 * (i - 1))) * 0.017453292F;
            float f1 = MathHelper.cos(f);

            return this.locX() + (double) f1 * 1.3D;
        }
    }

    private double v(int i) {
        return i <= 0 ? this.locY() + 3.0D : this.locY() + 2.2D;
    }

    private double w(int i) {
        if (i <= 0) {
            return this.locZ();
        } else {
            float f = (this.aI + (float) (180 * (i - 1))) * 0.017453292F;
            float f1 = MathHelper.sin(f);

            return this.locZ() + (double) f1 * 1.3D;
        }
    }

    private float a(float f, float f1, float f2) {
        float f3 = MathHelper.g(f1 - f);

        if (f3 > f2) {
            f3 = f2;
        }

        if (f3 < -f2) {
            f3 = -f2;
        }

        return f + f3;
    }

    private void a(int i, EntityLiving entityliving) {
        this.a(i, entityliving.locX(), entityliving.locY() + (double) entityliving.getHeadHeight() * 0.5D, entityliving.locZ(), i == 0 && this.random.nextFloat() < 0.001F);
    }

    private void a(int i, double d0, double d1, double d2, boolean flag) {
        this.world.a((EntityHuman) null, 1024, new BlockPosition(this), 0);
        double d3 = this.u(i);
        double d4 = this.v(i);
        double d5 = this.w(i);
        double d6 = d0 - d3;
        double d7 = d1 - d4;
        double d8 = d2 - d5;
        EntityWitherSkull entitywitherskull = new EntityWitherSkull(this.world, this, d6, d7, d8);

        if (flag) {
            entitywitherskull.setCharged(true);
        }

        entitywitherskull.setPositionRaw(d3, d4, d5);
        this.world.addEntity(entitywitherskull);
    }

    @Override
    public void a(EntityLiving entityliving, float f) {
        this.a(0, entityliving);
    }

    @Override
    public boolean damageEntity(DamageSource damagesource, float f) {
        if (this.isInvulnerable(damagesource)) {
            return false;
        } else if (damagesource != DamageSource.DROWN && !(damagesource.getEntity() instanceof EntityWither)) {
            if (this.eq() > 0 && damagesource != DamageSource.OUT_OF_WORLD) {
                return false;
            } else {
                Entity entity;

                if (this.J_()) {
                    entity = damagesource.j();
                    if (entity instanceof EntityArrow) {
                        return false;
                    }
                }

                entity = damagesource.getEntity();
                if (entity != null && !(entity instanceof EntityHuman) && entity instanceof EntityLiving && ((EntityLiving) entity).getMonsterType() == this.getMonsterType()) {
                    return false;
                } else {
                    if (this.bE <= 0) {
                        this.bE = 20;
                    }

                    for (int i = 0; i < this.bD.length; ++i) {
                        this.bD[i] += 3;
                    }

                    return super.damageEntity(damagesource, f);
                }
            }
        } else {
            return false;
        }
    }

    @Override
    protected void dropDeathLoot(DamageSource damagesource, int i, boolean flag) {
        super.dropDeathLoot(damagesource, i, flag);
        EntityItem entityitem = this.a((IMaterial) Items.NETHER_STAR);

        if (entityitem != null) {
            entityitem.r();
        }

    }

    @Override
    public void checkDespawn() {
        if (this.world.getDifficulty() == EnumDifficulty.PEACEFUL && this.J()) {
            this.die();
        } else {
            this.ticksFarFromPlayer = 0;
        }
    }

    @Override
    public boolean b(float f, float f1) {
        return false;
    }

    @Override
    public boolean addEffect(MobEffect mobeffect) {
        return false;
    }

    @Override
    protected void initAttributes() {
        super.initAttributes();
        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(300.0D);
        this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.6000000238418579D);
        this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(40.0D);
        this.getAttributeInstance(GenericAttributes.ARMOR).setValue(4.0D);
    }

    public int eq() {
        return (Integer) this.datawatcher.get(EntityWither.bx);
    }

    public void s(int i) {
        this.datawatcher.set(EntityWither.bx, i);
    }

    public int getHeadTarget(int i) {
        return (Integer) this.datawatcher.get((DataWatcherObject) EntityWither.bw.get(i));
    }

    public void setHeadTarget(int i, int j) {
        this.datawatcher.set((DataWatcherObject) EntityWither.bw.get(i), j);
    }

    public boolean J_() {
        return this.getHealth() <= this.getMaxHealth() / 2.0F;
    }

    @Override
    public EnumMonsterType getMonsterType() {
        return EnumMonsterType.UNDEAD;
    }

    @Override
    protected boolean n(Entity entity) {
        return false;
    }

    @Override
    public boolean canPortal() {
        return false;
    }

    @Override
    public boolean d(MobEffect mobeffect) {
        return mobeffect.getMobEffect() == MobEffects.WITHER ? false : super.d(mobeffect);
    }

    class a extends PathfinderGoal {

        public a() {
            this.a(EnumSet.of(PathfinderGoal.Type.MOVE, PathfinderGoal.Type.JUMP, PathfinderGoal.Type.LOOK));
        }

        @Override
        public boolean a() {
            return EntityWither.this.eq() > 0;
        }
    }
}