package net.minecraft.server;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
// CraftBukkit start
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
// CraftBukkit end
// PAIL: Fixme
public class EntityEnderDragon extends EntityInsentient implements IComplex, IMonster {
private static final Logger bI = LogManager.getLogger();
public static final DataWatcherObject<Integer> PHASE = DataWatcher.a(EntityEnderDragon.class, DataWatcherRegistry.b);
public double[][] b = new double[64][3];
public int c = -1;
public EntityComplexPart[] children;
public EntityComplexPart bv = new EntityComplexPart(this, "head", 6.0F, 6.0F);
public EntityComplexPart bw = new EntityComplexPart(this, "neck", 6.0F, 6.0F);
public EntityComplexPart bx = new EntityComplexPart(this, "body", 8.0F, 8.0F);
public EntityComplexPart by = new EntityComplexPart(this, "tail", 4.0F, 4.0F);
public EntityComplexPart bz = new EntityComplexPart(this, "tail", 4.0F, 4.0F);
public EntityComplexPart bA = new EntityComplexPart(this, "tail", 4.0F, 4.0F);
public EntityComplexPart bB = new EntityComplexPart(this, "wing", 4.0F, 4.0F);
public EntityComplexPart bC = new EntityComplexPart(this, "wing", 4.0F, 4.0F);
public float bD;
public float bE;
public boolean bF;
public int bG;
public EntityEnderCrystal currentEnderCrystal;
private final EnderDragonBattle bJ;
private final DragonControllerManager bK;
private int bL = 200;
private int bM;
private final PathPoint[] bN = new PathPoint[24];
private final int[] bO = new int[24];
private final Path bP = new Path();
private Explosion explosionSource = new Explosion(null, this, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, true); // CraftBukkit - reusable source for CraftTNTPrimed.getSource()
public EntityEnderDragon(World world) {
super(world);
this.children = new EntityComplexPart[] { this.bv, this.bw, this.bx, this.by, this.bz, this.bA, this.bB, this.bC};
this.setHealth(this.getMaxHealth());
this.setSize(16.0F, 8.0F);
this.noclip = true;
this.fireProof = true;
this.bL = 100;
this.ah = true;
if (!world.isClientSide && world.worldProvider instanceof WorldProviderTheEnd) {
this.bJ = ((WorldProviderTheEnd) world.worldProvider).t();
} else {
this.bJ = null;
}
this.bK = new DragonControllerManager(this);
}
protected void initAttributes() {
super.initAttributes();
this.getAttributeInstance(GenericAttributes.maxHealth).setValue(200.0D);
}
protected void i() {
super.i();
this.getDataWatcher().register(EntityEnderDragon.PHASE, Integer.valueOf(DragonControllerPhase.k.b()));
}
public double[] a(int i, float f) {
if (this.getHealth() <= 0.0F) {
f = 0.0F;
}
f = 1.0F - f;
int j = this.c - i & 63;
int k = this.c - i - 1 & 63;
double[] adouble = new double[3];
double d0 = this.b[j][0];
double d1 = MathHelper.g(this.b[k][0] - d0);
adouble[0] = d0 + d1 * (double) f;
d0 = this.b[j][1];
d1 = this.b[k][1] - d0;
adouble[1] = d0 + d1 * (double) f;
adouble[2] = this.b[j][2] + (this.b[k][2] - this.b[j][2]) * (double) f;
return adouble;
}
public void n() {
float f;
float f1;
if (this.world.isClientSide) {
this.setHealth(this.getHealth());
if (!this.isSilent()) {
f = MathHelper.cos(this.bE * 6.2831855F);
f1 = MathHelper.cos(this.bD * 6.2831855F);
if (f1 <= -0.3F && f >= -0.3F) {
this.world.a(this.locX, this.locY, this.locZ, SoundEffects.aU, this.bC(), 5.0F, 0.8F + this.random.nextFloat() * 0.3F, false);
}
if (!this.bK.a().a() && --this.bL < 0) {
this.world.a(this.locX, this.locY, this.locZ, SoundEffects.aV, this.bC(), 2.5F, 0.8F + this.random.nextFloat() * 0.3F, false);
this.bL = 200 + this.random.nextInt(200);
}
}
}
this.bD = this.bE;
float f2;
if (this.getHealth() <= 0.0F) {
f = (this.random.nextFloat() - 0.5F) * 8.0F;
f1 = (this.random.nextFloat() - 0.5F) * 4.0F;
f2 = (this.random.nextFloat() - 0.5F) * 8.0F;
this.world.addParticle(EnumParticle.EXPLOSION_LARGE, this.locX + (double) f, this.locY + 2.0D + (double) f1, this.locZ + (double) f2, 0.0D, 0.0D, 0.0D, new int[0]);
} else {
this.dc();
f = 0.2F / (MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ) * 10.0F + 1.0F);
f *= (float) Math.pow(2.0D, this.motY);
if (this.bK.a().a()) {
this.bE += 0.1F;
} else if (this.bF) {
this.bE += f * 0.5F;
} else {
this.bE += f;
}
this.yaw = MathHelper.g(this.yaw);
if (this.hasAI()) {
this.bE = 0.5F;
} else {
if (this.c < 0) {
for (int i = 0; i < this.b.length; ++i) {
this.b[i][0] = (double) this.yaw;
this.b[i][1] = this.locY;
}
}
if (++this.c == this.b.length) {
this.c = 0;
}
this.b[this.c][0] = (double) this.yaw;
this.b[this.c][1] = this.locY;
double d0;
double d1;
double d2;
float f3;
float f4;
if (this.world.isClientSide) {
if (this.bh > 0) {
double d3 = this.locX + (this.bi - this.locX) / (double) this.bh;
d0 = this.locY + (this.bj - this.locY) / (double) this.bh;
d1 = this.locZ + (this.bk - this.locZ) / (double) this.bh;
d2 = MathHelper.g(this.bl - (double) this.yaw);
this.yaw = (float) ((double) this.yaw + d2 / (double) this.bh);
this.pitch = (float) ((double) this.pitch + (this.bm - (double) this.pitch) / (double) this.bh);
--this.bh;
this.setPosition(d3, d0, d1);
this.setYawPitch(this.yaw, this.pitch);
}
this.bK.a().b();
} else {
IDragonController idragoncontroller = this.bK.a();
idragoncontroller.c();
if (this.bK.a() != idragoncontroller) {
idragoncontroller = this.bK.a();
idragoncontroller.c();
}
Vec3D vec3d = idragoncontroller.g();
if (vec3d != null && idragoncontroller.getControllerPhase() != DragonControllerPhase.k) { // CraftBukkit - Don't move when hovering // PAIL: rename
d0 = vec3d.x - this.locX;
d1 = vec3d.y - this.locY;
d2 = vec3d.z - this.locZ;
double d4 = d0 * d0 + d1 * d1 + d2 * d2;
f3 = idragoncontroller.f();
d1 = MathHelper.a(d1 / (double) MathHelper.sqrt(d0 * d0 + d2 * d2), (double) (-f3), (double) f3);
this.motY += d1 * 0.10000000149011612D;
this.yaw = MathHelper.g(this.yaw);
double d5 = MathHelper.a(MathHelper.g(180.0D - MathHelper.c(d0, d2) * 57.2957763671875D - (double) this.yaw), -50.0D, 50.0D);
Vec3D vec3d1 = (new Vec3D(vec3d.x - this.locX, vec3d.y - this.locY, vec3d.z - this.locZ)).a();
Vec3D vec3d2 = (new Vec3D((double) MathHelper.sin(this.yaw * 0.017453292F), this.motY, (double) (-MathHelper.cos(this.yaw * 0.017453292F)))).a();
f4 = Math.max(((float) vec3d2.b(vec3d1) + 0.5F) / 1.5F, 0.0F);
this.bg *= 0.8F;
this.bg = (float) ((double) this.bg + d5 * (double) idragoncontroller.h());
this.yaw += this.bg * 0.1F;
float f5 = (float) (2.0D / (d4 + 1.0D));
float f6 = 0.06F;
this.a(0.0F, -1.0F, 0.06F * (f4 * f5 + (1.0F - f5)));
if (this.bF) {
this.move(EnumMoveType.SELF, this.motX * 0.800000011920929D, this.motY * 0.800000011920929D, this.motZ * 0.800000011920929D);
} else {
this.move(EnumMoveType.SELF, this.motX, this.motY, this.motZ);
}
Vec3D vec3d3 = (new Vec3D(this.motX, this.motY, this.motZ)).a();
float f7 = ((float) vec3d3.b(vec3d2) + 1.0F) / 2.0F;
f7 = 0.8F + 0.15F * f7;
this.motX *= (double) f7;
this.motZ *= (double) f7;
this.motY *= 0.9100000262260437D;
}
}
this.aN = this.yaw;
this.bv.width = 1.0F;
this.bv.length = 1.0F;
this.bw.width = 3.0F;
this.bw.length = 3.0F;
this.by.width = 2.0F;
this.by.length = 2.0F;
this.bz.width = 2.0F;
this.bz.length = 2.0F;
this.bA.width = 2.0F;
this.bA.length = 2.0F;
this.bx.length = 3.0F;
this.bx.width = 5.0F;
this.bB.length = 2.0F;
this.bB.width = 4.0F;
this.bC.length = 3.0F;
this.bC.width = 4.0F;
Vec3D[] avec3d = new Vec3D[this.children.length];
for (int j = 0; j < this.children.length; ++j) {
avec3d[j] = new Vec3D(this.children[j].locX, this.children[j].locY, this.children[j].locZ);
}
f2 = (float) (this.a(5, 1.0F)[1] - this.a(10, 1.0F)[1]) * 10.0F * 0.017453292F;
float f8 = MathHelper.cos(f2);
float f9 = MathHelper.sin(f2);
float f10 = this.yaw * 0.017453292F;
float f11 = MathHelper.sin(f10);
float f12 = MathHelper.cos(f10);
this.bx.A_();
this.bx.setPositionRotation(this.locX + (double) (f11 * 0.5F), this.locY, this.locZ - (double) (f12 * 0.5F), 0.0F, 0.0F);
this.bB.A_();
this.bB.setPositionRotation(this.locX + (double) (f12 * 4.5F), this.locY + 2.0D, this.locZ + (double) (f11 * 4.5F), 0.0F, 0.0F);
this.bC.A_();
this.bC.setPositionRotation(this.locX - (double) (f12 * 4.5F), this.locY + 2.0D, this.locZ - (double) (f11 * 4.5F), 0.0F, 0.0F);
if (!this.world.isClientSide && this.hurtTicks == 0) {
this.a(this.world.getEntities(this, this.bB.getBoundingBox().grow(4.0D, 2.0D, 4.0D).d(0.0D, -2.0D, 0.0D)));
this.a(this.world.getEntities(this, this.bC.getBoundingBox().grow(4.0D, 2.0D, 4.0D).d(0.0D, -2.0D, 0.0D)));
this.b(this.world.getEntities(this, this.bv.getBoundingBox().g(1.0D)));
this.b(this.world.getEntities(this, this.bw.getBoundingBox().g(1.0D)));
}
double[] adouble = this.a(5, 1.0F);
float f13 = MathHelper.sin(this.yaw * 0.017453292F - this.bg * 0.01F);
float f14 = MathHelper.cos(this.yaw * 0.017453292F - this.bg * 0.01F);
this.bv.A_();
this.bw.A_();
f3 = this.q(1.0F);
this.bv.setPositionRotation(this.locX + (double) (f13 * 6.5F * f8), this.locY + (double) f3 + (double) (f9 * 6.5F), this.locZ - (double) (f14 * 6.5F * f8), 0.0F, 0.0F);
this.bw.setPositionRotation(this.locX + (double) (f13 * 5.5F * f8), this.locY + (double) f3 + (double) (f9 * 5.5F), this.locZ - (double) (f14 * 5.5F * f8), 0.0F, 0.0F);
int k;
for (k = 0; k < 3; ++k) {
EntityComplexPart entitycomplexpart = null;
if (k == 0) {
entitycomplexpart = this.by;
}
if (k == 1) {
entitycomplexpart = this.bz;
}
if (k == 2) {
entitycomplexpart = this.bA;
}
double[] adouble1 = this.a(12 + k * 2, 1.0F);
float f15 = this.yaw * 0.017453292F + this.c(adouble1[0] - adouble[0]) * 0.017453292F;
float f16 = MathHelper.sin(f15);
float f17 = MathHelper.cos(f15);
float f18 = 1.5F;
f4 = (float) (k + 1) * 2.0F;
entitycomplexpart.A_();
entitycomplexpart.setPositionRotation(this.locX - (double) ((f11 * 1.5F + f16 * f4) * f8), this.locY + (adouble1[1] - adouble[1]) - (double) ((f4 + 1.5F) * f9) + 1.5D, this.locZ + (double) ((f12 * 1.5F + f17 * f4) * f8), 0.0F, 0.0F);
}
if (!this.world.isClientSide) {
this.bF = this.b(this.bv.getBoundingBox()) | this.b(this.bw.getBoundingBox()) | this.b(this.bx.getBoundingBox());
if (this.bJ != null) {
this.bJ.b(this);
}
}
for (k = 0; k < this.children.length; ++k) {
this.children[k].lastX = avec3d[k].x;
this.children[k].lastY = avec3d[k].y;
this.children[k].lastZ = avec3d[k].z;
}
}
}
}
private float q(float f) {
double d0;
if (this.bK.a().a()) {
d0 = -1.0D;
} else {
double[] adouble = this.a(5, 1.0F);
double[] adouble1 = this.a(0, 1.0F);
d0 = adouble[1] - adouble1[1];
}
return (float) d0;
}
private void dc() {
if (this.currentEnderCrystal != null) {
if (this.currentEnderCrystal.dead) {
this.currentEnderCrystal = null;
} else if (this.ticksLived % 10 == 0 && this.getHealth() < this.getMaxHealth()) {
// CraftBukkit start
EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), 1.0F, EntityRegainHealthEvent.RegainReason.ENDER_CRYSTAL);
this.world.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
this.setHealth((float) (this.getHealth() + event.getAmount()));
}
// CraftBukkit end
}
}
if (this.random.nextInt(10) == 0) {
List list = this.world.a(EntityEnderCrystal.class, this.getBoundingBox().g(32.0D));
EntityEnderCrystal entityendercrystal = null;
double d0 = Double.MAX_VALUE;
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
EntityEnderCrystal entityendercrystal1 = (EntityEnderCrystal) iterator.next();
double d1 = entityendercrystal1.h(this);
if (d1 < d0) {
d0 = d1;
entityendercrystal = entityendercrystal1;
}
}
this.currentEnderCrystal = entityendercrystal;
}
}
private void a(List<Entity> list) {
double d0 = (this.bx.getBoundingBox().a + this.bx.getBoundingBox().d) / 2.0D;
double d1 = (this.bx.getBoundingBox().c + this.bx.getBoundingBox().f) / 2.0D;
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
if (entity instanceof EntityLiving) {
double d2 = entity.locX - d0;
double d3 = entity.locZ - d1;
double d4 = d2 * d2 + d3 * d3;
entity.f(d2 / d4 * 4.0D, 0.20000000298023224D, d3 / d4 * 4.0D);
if (!this.bK.a().a() && ((EntityLiving) entity).bL() < entity.ticksLived - 2) {
entity.damageEntity(DamageSource.mobAttack(this), 5.0F);
this.a((EntityLiving) this, entity);
}
}
}
}
private void b(List<Entity> list) {
for (int i = 0; i < list.size(); ++i) {
Entity entity = (Entity) list.get(i);
if (entity instanceof EntityLiving) {
entity.damageEntity(DamageSource.mobAttack(this), 10.0F);
this.a((EntityLiving) this, entity);
}
}
}
private float c(double d0) {
return (float) MathHelper.g(d0);
}
private boolean b(AxisAlignedBB axisalignedbb) {
int i = MathHelper.floor(axisalignedbb.a);
int j = MathHelper.floor(axisalignedbb.b);
int k = MathHelper.floor(axisalignedbb.c);
int l = MathHelper.floor(axisalignedbb.d);
int i1 = MathHelper.floor(axisalignedbb.e);
int j1 = MathHelper.floor(axisalignedbb.f);
boolean flag = false;
boolean flag1 = false;
// CraftBukkit start - Create a list to hold all the destroyed blocks
List<org.bukkit.block.Block> destroyedBlocks = new java.util.ArrayList<org.bukkit.block.Block>();
org.bukkit.craftbukkit.CraftWorld craftWorld = this.world.getWorld();
// CraftBukkit end
for (int k1 = i; k1 <= l; ++k1) {
for (int l1 = j; l1 <= i1; ++l1) {
for (int i2 = k; i2 <= j1; ++i2) {
BlockPosition blockposition = new BlockPosition(k1, l1, i2);
IBlockData iblockdata = this.world.getType(blockposition);
Block block = iblockdata.getBlock();
if (iblockdata.getMaterial() != Material.AIR && iblockdata.getMaterial() != Material.FIRE) {
if (!this.world.getGameRules().getBoolean("mobGriefing")) {
flag = true;
} else if (block != Blocks.BARRIER && block != Blocks.OBSIDIAN && block != Blocks.END_STONE && block != Blocks.BEDROCK && block != Blocks.END_PORTAL && block != Blocks.END_PORTAL_FRAME) {
if (block != Blocks.COMMAND_BLOCK && block != Blocks.dc && block != Blocks.dd && block != Blocks.IRON_BARS && block != Blocks.END_GATEWAY) {
// CraftBukkit start - Add blocks to list rather than destroying them
// flag1 = this.world.setAir(blockposition) || flag1;
flag1 = true;
destroyedBlocks.add(craftWorld.getBlockAt(k1, l1, i2));
// CraftBukkit end
} else {
flag = true;
}
} else {
flag = true;
}
}
}
}
}
// CraftBukkit start - Set off an EntityExplodeEvent for the dragon exploding all these blocks
org.bukkit.entity.Entity bukkitEntity = this.getBukkitEntity();
EntityExplodeEvent event = new EntityExplodeEvent(bukkitEntity, bukkitEntity.getLocation(), destroyedBlocks, 0F);
bukkitEntity.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
// This flag literally means 'Dragon hit something hard' (Obsidian, White Stone or Bedrock) and will cause the dragon to slow down.
// We should consider adding an event extension for it, or perhaps returning true if the event is cancelled.
return flag;
} else if (event.getYield() == 0F) {
// Yield zero ==> no drops
for (org.bukkit.block.Block block : event.blockList()) {
this.world.setAir(new BlockPosition(block.getX(), block.getY(), block.getZ()));
}
} else {
for (org.bukkit.block.Block block : event.blockList()) {
org.bukkit.Material blockId = block.getType();
if (blockId == org.bukkit.Material.AIR) {
continue;
}
int blockX = block.getX();
int blockY = block.getY();
int blockZ = block.getZ();
Block nmsBlock = org.bukkit.craftbukkit.util.CraftMagicNumbers.getBlock(blockId);
if (nmsBlock.a(explosionSource)) {
nmsBlock.dropNaturally(this.world, new BlockPosition(blockX, blockY, blockZ), nmsBlock.fromLegacyData(block.getData()), event.getYield(), 0);
}
nmsBlock.wasExploded(world, new BlockPosition(blockX, blockY, blockZ), explosionSource);
this.world.setAir(new BlockPosition(blockX, blockY, blockZ));
}
}
// CraftBukkit end
if (flag1) {
double d0 = axisalignedbb.a + (axisalignedbb.d - axisalignedbb.a) * (double) this.random.nextFloat();
double d1 = axisalignedbb.b + (axisalignedbb.e - axisalignedbb.b) * (double) this.random.nextFloat();
double d2 = axisalignedbb.c + (axisalignedbb.f - axisalignedbb.c) * (double) this.random.nextFloat();
this.world.addParticle(EnumParticle.EXPLOSION_LARGE, d0, d1, d2, 0.0D, 0.0D, 0.0D, new int[0]);
}
return flag;
}
public boolean a(EntityComplexPart entitycomplexpart, DamageSource damagesource, float f) {
f = this.bK.a().a(entitycomplexpart, damagesource, f);
if (entitycomplexpart != this.bv) {
f = f / 4.0F + Math.min(f, 1.0F);
}
if (f < 0.01F) {
return false;
} else {
if (damagesource.getEntity() instanceof EntityHuman || damagesource.isExplosion()) {
float f1 = this.getHealth();
this.dealDamage(damagesource, f);
if (this.getHealth() <= 0.0F && !this.bK.a().a()) {
this.setHealth(1.0F);
this.bK.setControllerPhase(DragonControllerPhase.j);
}
if (this.bK.a().a()) {
this.bM = (int) ((float) this.bM + (f1 - this.getHealth()));
if ((float) this.bM > 0.25F * this.getMaxHealth()) {
this.bM = 0;
this.bK.setControllerPhase(DragonControllerPhase.e);
}
}
}
return true;
}
}
public boolean damageEntity(DamageSource damagesource, float f) {
if (damagesource instanceof EntityDamageSource && ((EntityDamageSource) damagesource).x()) {
this.a(this.bx, damagesource, f);
}
return false;
}
protected boolean dealDamage(DamageSource damagesource, float f) {
return super.damageEntity(damagesource, f);
}
public void Q() {
this.die();
if (this.bJ != null) {
this.bJ.b(this);
this.bJ.a(this);
}
}
protected void bG() {
if (this.bJ != null) {
this.bJ.b(this);
}
++this.bG;
if (this.bG >= 180 && this.bG <= 200) {
float f = (this.random.nextFloat() - 0.5F) * 8.0F;
float f1 = (this.random.nextFloat() - 0.5F) * 4.0F;
float f2 = (this.random.nextFloat() - 0.5F) * 8.0F;
this.world.addParticle(EnumParticle.EXPLOSION_HUGE, this.locX + (double) f, this.locY + 2.0D + (double) f1, this.locZ + (double) f2, 0.0D, 0.0D, 0.0D, new int[0]);
}
boolean flag = this.world.getGameRules().getBoolean("doMobLoot");
short short0 = 500;
if (this.bJ != null && !this.bJ.d()) {
short0 = 12000;
}
if (!this.world.isClientSide) {
if (this.bG > 150 && this.bG % 5 == 0 && flag) {
this.a(MathHelper.d((float) short0 * 0.08F));
}
if (this.bG == 1) {
// CraftBukkit start - Use relative location for far away sounds
// this.world.a(1028, new BlockPosition(this), 0);
// Paper start
//int viewDistance = ((WorldServer) this.world).spigotConfig.viewDistance * 16; // Paper - updated to use worlds actual view distance incase we have to uncomment this due to removal of player view distance API
for (EntityHuman human : world.players) {
EntityPlayer player = (EntityPlayer) human;
int viewDistance = player.getViewDistance();
// Paper end
double deltaX = this.locX - player.locX;
double deltaZ = this.locZ - player.locZ;
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
if ( world.spigotConfig.dragonDeathSoundRadius > 0 && distanceSquared > world.spigotConfig.dragonDeathSoundRadius * world.spigotConfig.dragonDeathSoundRadius ) continue; // Spigot
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(1028, new BlockPosition((int) relativeX, (int) this.locY, (int) relativeZ), 0, true));
} else {
player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1028, new BlockPosition((int) this.locX, (int) this.locY, (int) this.locZ), 0, true));
}
}
// CraftBukkit end
}
}
this.move(EnumMoveType.SELF, 0.0D, 0.10000000149011612D, 0.0D);
this.yaw += 20.0F;
this.aN = this.yaw;
if (this.bG == 200 && !this.world.isClientSide) {
if (flag) {
this.a(MathHelper.d((float) short0 * 0.2F));
}
if (this.bJ != null) {
this.bJ.a(this);
}
this.die();
}
}
private void a(int i) {
while (i > 0) {
int j = EntityExperienceOrb.getOrbValue(i);
i -= j;
this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j));
}
}
public int o() {
if (this.bN[0] == null) {
for (int i = 0; i < 24; ++i) {
int j = 5;
int k;
int l;
if (i < 12) {
k = (int) (60.0F * MathHelper.cos(2.0F * (-3.1415927F + 0.2617994F * (float) i)));
l = (int) (60.0F * MathHelper.sin(2.0F * (-3.1415927F + 0.2617994F * (float) i)));
} else {
int i1;
if (i < 20) {
i1 = i - 12;
k = (int) (40.0F * MathHelper.cos(2.0F * (-3.1415927F + 0.3926991F * (float) i1)));
l = (int) (40.0F * MathHelper.sin(2.0F * (-3.1415927F + 0.3926991F * (float) i1)));
j += 10;
} else {
i1 = i - 20;
k = (int) (20.0F * MathHelper.cos(2.0F * (-3.1415927F + 0.7853982F * (float) i1)));
l = (int) (20.0F * MathHelper.sin(2.0F * (-3.1415927F + 0.7853982F * (float) i1)));
}
}
int j1 = Math.max(this.world.K() + 10, this.world.q(new BlockPosition(k, 0, l)).getY() + j);
this.bN[i] = new PathPoint(k, j1, l);
}
this.bO[0] = 6146;
this.bO[1] = 8197;
this.bO[2] = 8202;
this.bO[3] = 16404;
this.bO[4] = '\u8028';
this.bO[5] = '\u8050';
this.bO[6] = 65696;
this.bO[7] = 131392;
this.bO[8] = 131712;
this.bO[9] = 263424;
this.bO[10] = 526848;
this.bO[11] = 525313;
this.bO[12] = 1581057;
this.bO[13] = 3166214;
this.bO[14] = 2138120;
this.bO[15] = 6373424;
this.bO[16] = 4358208;
this.bO[17] = 12910976;
this.bO[18] = 9044480;
this.bO[19] = 9706496;
this.bO[20] = 15216640;
this.bO[21] = 13688832;
this.bO[22] = 11763712;
this.bO[23] = 8257536;
}
return this.k(this.locX, this.locY, this.locZ);
}
public int k(double d0, double d1, double d2) {
float f = 10000.0F;
int i = 0;
PathPoint pathpoint = new PathPoint(MathHelper.floor(d0), MathHelper.floor(d1), MathHelper.floor(d2));
byte b0 = 0;
if (this.bJ == null || this.bJ.c() == 0) {
b0 = 12;
}
for (int j = b0; j < 24; ++j) {
if (this.bN[j] != null) {
float f1 = this.bN[j].b(pathpoint);
if (f1 < f) {
f = f1;
i = j;
}
}
}
return i;
}
@Nullable
public PathEntity a(int i, int j, @Nullable PathPoint pathpoint) {
PathPoint pathpoint1;
for (int k = 0; k < 24; ++k) {
pathpoint1 = this.bN[k];
pathpoint1.i = false;
pathpoint1.g = 0.0F;
pathpoint1.e = 0.0F;
pathpoint1.f = 0.0F;
pathpoint1.h = null;
pathpoint1.d = -1;
}
PathPoint pathpoint2 = this.bN[i];
pathpoint1 = this.bN[j];
pathpoint2.e = 0.0F;
pathpoint2.f = pathpoint2.a(pathpoint1);
pathpoint2.g = pathpoint2.f;
this.bP.a();
this.bP.a(pathpoint2);
PathPoint pathpoint3 = pathpoint2;
byte b0 = 0;
if (this.bJ == null || this.bJ.c() == 0) {
b0 = 12;
}
label70:
while (!this.bP.e()) {
PathPoint pathpoint4 = this.bP.c();
if (pathpoint4.equals(pathpoint1)) {
if (pathpoint != null) {
pathpoint.h = pathpoint1;
pathpoint1 = pathpoint;
}
return this.a(pathpoint2, pathpoint1);
}
if (pathpoint4.a(pathpoint1) < pathpoint3.a(pathpoint1)) {
pathpoint3 = pathpoint4;
}
pathpoint4.i = true;
int l = 0;
int i1 = 0;
while (true) {
if (i1 < 24) {
if (this.bN[i1] != pathpoint4) {
++i1;
continue;
}
l = i1;
}
i1 = b0;
while (true) {
if (i1 >= 24) {
continue label70;
}
if ((this.bO[l] & 1 << i1) > 0) {
PathPoint pathpoint5 = this.bN[i1];
if (!pathpoint5.i) {
float f = pathpoint4.e + pathpoint4.a(pathpoint5);
if (!pathpoint5.a() || f < pathpoint5.e) {
pathpoint5.h = pathpoint4;
pathpoint5.e = f;
pathpoint5.f = pathpoint5.a(pathpoint1);
if (pathpoint5.a()) {
this.bP.a(pathpoint5, pathpoint5.e + pathpoint5.f);
} else {
pathpoint5.g = pathpoint5.e + pathpoint5.f;
this.bP.a(pathpoint5);
}
}
}
}
++i1;
}
}
}
if (pathpoint3 == pathpoint2) {
return null;
} else {
EntityEnderDragon.bI.debug("Failed to find path from {} to {}", new Object[] { Integer.valueOf(i), Integer.valueOf(j)});
if (pathpoint != null) {
pathpoint.h = pathpoint3;
pathpoint3 = pathpoint;
}
return this.a(pathpoint2, pathpoint3);
}
}
private PathEntity a(PathPoint pathpoint, PathPoint pathpoint1) {
int i = 1;
PathPoint pathpoint2;
for (pathpoint2 = pathpoint1; pathpoint2.h != null; pathpoint2 = pathpoint2.h) {
++i;
}
PathPoint[] apathpoint = new PathPoint[i];
pathpoint2 = pathpoint1;
--i;
for (apathpoint[i] = pathpoint1; pathpoint2.h != null; apathpoint[i] = pathpoint2) {
pathpoint2 = pathpoint2.h;
--i;
}
return new PathEntity(apathpoint);
}
public static void a(DataConverterManager dataconvertermanager) {
EntityInsentient.a(dataconvertermanager, EntityEnderDragon.class);
}
public void b(NBTTagCompound nbttagcompound) {
super.b(nbttagcompound);
nbttagcompound.setInt("DragonPhase", this.bK.a().getControllerPhase().b());
}
public void a(NBTTagCompound nbttagcompound) {
super.a(nbttagcompound);
if (nbttagcompound.hasKey("DragonPhase")) {
this.bK.setControllerPhase(DragonControllerPhase.getById(nbttagcompound.getInt("DragonPhase")));
}
}
protected void L() {}
public Entity[] aT() {
return this.children;
}
public boolean isInteractable() {
return false;
}
public World a() {
return this.world;
}
public SoundCategory bC() {
return SoundCategory.HOSTILE;
}
protected SoundEffect G() {
return SoundEffects.aR;
}
protected SoundEffect bW() {
return SoundEffects.aW;
}
protected float ci() {
return 5.0F;
}
@Nullable
protected MinecraftKey J() {
return LootTables.ay;
}
public Vec3D a(float f) {
IDragonController idragoncontroller = this.bK.a();
DragonControllerPhase dragoncontrollerphase = idragoncontroller.getControllerPhase();
Vec3D vec3d;
float f1;
if (dragoncontrollerphase != DragonControllerPhase.d && dragoncontrollerphase != DragonControllerPhase.e) {
if (idragoncontroller.a()) {
float f2 = this.pitch;
f1 = 1.5F;
this.pitch = -45.0F;
vec3d = this.f(f);
this.pitch = f2;
} else {
vec3d = this.f(f);
}
} else {
BlockPosition blockposition = this.world.q(WorldGenEndTrophy.a);
f1 = Math.max(MathHelper.sqrt(this.d(blockposition)) / 4.0F, 1.0F);
float f3 = 6.0F / f1;
float f4 = this.pitch;
float f5 = 1.5F;
this.pitch = -f3 * 1.5F * 5.0F;
vec3d = this.f(f);
this.pitch = f4;
}
return vec3d;
}
public void a(EntityEnderCrystal entityendercrystal, BlockPosition blockposition, DamageSource damagesource) {
EntityHuman entityhuman;
if (damagesource.getEntity() instanceof EntityHuman) {
entityhuman = (EntityHuman) damagesource.getEntity();
} else {
entityhuman = this.world.a(blockposition, 64.0D, 64.0D);
}
if (entityendercrystal == this.currentEnderCrystal) {
this.a(this.bv, DamageSource.b(entityhuman), 10.0F);
}
this.bK.a().a(entityendercrystal, blockposition, damagesource, entityhuman);
}
public void a(DataWatcherObject<?> datawatcherobject) {
if (EntityEnderDragon.PHASE.equals(datawatcherobject) && this.world.isClientSide) {
this.bK.setControllerPhase(DragonControllerPhase.getById(((Integer) this.getDataWatcher().get(EntityEnderDragon.PHASE)).intValue()));
}
super.a(datawatcherobject);
}
public DragonControllerManager getDragonControllerManager() {
return this.bK;
}
@Nullable
public EnderDragonBattle db() {
return this.bJ;
}
public void addEffect(MobEffect mobeffect) {}
protected boolean n(Entity entity) {
return false;
}
public boolean aX() {
return false;
}
}