After the changes in d611cff2 we started including a mob's equipment when calling EntityDeathEvent so plugins can access this data. However, the changes to enable this triggered a bug that makes skeletons and pig zombies no longer drop equipment because they handle this differently than the rest. On top of this we don't handle dropping equipment for mobs that cannot pick up items in vanilla even though vanilla does drop equipment for them if you summon them with it. We also do not include a horse's inventory in the event so they drop their saddle, armor, chest, and chest contents with no way for a plugin to control this. To solve this issues we revert mob item dropping back to vanilla logic and instead just capture all their drops in the method they all call to spawn them into the world. We also move horse inventory dropping so it happens at a time when we're capturing these drops. With these changes all items mobs drop on death should now be included in the event and we have less diff to worry about for future updates.
1632 lines
51 KiB
Java
1632 lines
51 KiB
Java
package net.minecraft.server;
|
|
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Random;
|
|
import java.util.UUID;
|
|
|
|
// CraftBukkit start
|
|
import java.util.ArrayList;
|
|
import org.bukkit.craftbukkit.event.CraftEventFactory;
|
|
import org.bukkit.event.entity.EntityDamageEvent;
|
|
import org.bukkit.event.entity.EntityRegainHealthEvent;
|
|
// CraftBukkit end
|
|
|
|
public abstract class EntityLiving extends Entity {
|
|
|
|
private static final UUID b = UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D");
|
|
private static final AttributeModifier c = (new AttributeModifier(b, "Sprinting speed boost", 0.30000001192092896D, 2)).a(false);
|
|
private AttributeMapBase d;
|
|
public CombatTracker combatTracker = new CombatTracker(this); // CraftBukkit - private -> public, remove final
|
|
public final HashMap effects = new HashMap(); // CraftBukkit - protected -> public
|
|
private final ItemStack[] g = new ItemStack[5];
|
|
public boolean at;
|
|
public int au;
|
|
public int av;
|
|
public float aw;
|
|
public int hurtTicks;
|
|
public int ay;
|
|
public float az;
|
|
public int deathTicks;
|
|
public int attackTicks;
|
|
public float aC;
|
|
public float aD;
|
|
public float aE;
|
|
public float aF;
|
|
public float aG;
|
|
public int maxNoDamageTicks = 20;
|
|
public float aI;
|
|
public float aJ;
|
|
public float aK;
|
|
public float aL;
|
|
public float aM;
|
|
public float aN;
|
|
public float aO;
|
|
public float aP;
|
|
public float aQ = 0.02F;
|
|
public EntityHuman killer; // CraftBukkit - protected -> public
|
|
protected int lastDamageByPlayerTime;
|
|
protected boolean aT;
|
|
protected int aU;
|
|
protected float aV;
|
|
protected float aW;
|
|
protected float aX;
|
|
protected float aY;
|
|
protected float aZ;
|
|
protected int ba;
|
|
public float lastDamage; // CraftBukkit - protected -> public
|
|
protected boolean bc;
|
|
public float bd;
|
|
public float be;
|
|
protected float bf;
|
|
protected int bg;
|
|
protected double bh;
|
|
protected double bi;
|
|
protected double bj;
|
|
protected double bk;
|
|
protected double bl;
|
|
public boolean updateEffects = true; // CraftBukkit - private -> public
|
|
public EntityLiving lastDamager; // CraftBukkit - private -> public
|
|
private int bm;
|
|
private EntityLiving bn;
|
|
private int bo;
|
|
private float bp;
|
|
private int bq;
|
|
private float br;
|
|
// CraftBukkit start
|
|
public int expToDrop;
|
|
public int maxAirTicks = 300;
|
|
ArrayList<org.bukkit.inventory.ItemStack> drops = null;
|
|
// CraftBukkit end
|
|
|
|
public EntityLiving(World world) {
|
|
super(world);
|
|
this.aC();
|
|
// CraftBukkit - setHealth(getMaxHealth()) inlined and simplified to skip the instanceof check for EntityPlayer, as getBukkitEntity() is not initialized in constructor
|
|
this.datawatcher.watch(6, (float) this.getAttributeInstance(GenericAttributes.a).getValue());
|
|
this.k = true;
|
|
this.aL = (float) (Math.random() + 1.0D) * 0.01F;
|
|
this.setPosition(this.locX, this.locY, this.locZ);
|
|
this.aK = (float) Math.random() * 12398.0F;
|
|
this.yaw = (float) (Math.random() * 3.1415927410125732D * 2.0D);
|
|
this.aO = this.yaw;
|
|
this.W = 0.5F;
|
|
}
|
|
|
|
protected void c() {
|
|
this.datawatcher.a(7, Integer.valueOf(0));
|
|
this.datawatcher.a(8, Byte.valueOf((byte) 0));
|
|
this.datawatcher.a(9, Byte.valueOf((byte) 0));
|
|
this.datawatcher.a(6, Float.valueOf(1.0F));
|
|
}
|
|
|
|
protected void aC() {
|
|
this.bb().b(GenericAttributes.a);
|
|
this.bb().b(GenericAttributes.c);
|
|
this.bb().b(GenericAttributes.d);
|
|
if (!this.bj()) {
|
|
this.getAttributeInstance(GenericAttributes.d).setValue(0.10000000149011612D);
|
|
}
|
|
}
|
|
|
|
protected void a(double d0, boolean flag) {
|
|
if (!this.L()) {
|
|
this.M();
|
|
}
|
|
|
|
if (flag && this.fallDistance > 0.0F) {
|
|
int i = MathHelper.floor(this.locX);
|
|
int j = MathHelper.floor(this.locY - 0.20000000298023224D - (double) this.height);
|
|
int k = MathHelper.floor(this.locZ);
|
|
Block block = this.world.getType(i, j, k);
|
|
|
|
if (block.getMaterial() == Material.AIR) {
|
|
int l = this.world.getType(i, j - 1, k).b();
|
|
|
|
if (l == 11 || l == 32 || l == 21) {
|
|
block = this.world.getType(i, j - 1, k);
|
|
}
|
|
} else if (!this.world.isStatic && this.fallDistance > 3.0F) {
|
|
// CraftBukkit start - supply player as argument in particles for visibility API to work
|
|
if (this instanceof EntityPlayer) {
|
|
this.world.a((EntityHuman) this, 2006, i, j, k, MathHelper.f(this.fallDistance - 3.0F));
|
|
((EntityPlayer) this).playerConnection.sendPacket(new PacketPlayOutWorldEvent(2006, i, j, k, MathHelper.f(this.fallDistance - 3.0F), false));
|
|
} else {
|
|
this.world.triggerEffect(2006, i, j, k, MathHelper.f(this.fallDistance - 3.0F));
|
|
}
|
|
// CraftBukkit end
|
|
}
|
|
|
|
block.a(this.world, i, j, k, this, this.fallDistance);
|
|
}
|
|
|
|
super.a(d0, flag);
|
|
}
|
|
|
|
public boolean aD() {
|
|
return false;
|
|
}
|
|
|
|
public void B() {
|
|
this.aC = this.aD;
|
|
super.B();
|
|
this.world.methodProfiler.a("livingEntityBaseTick");
|
|
if (this.isAlive() && this.inBlock()) {
|
|
this.damageEntity(DamageSource.STUCK, 1.0F);
|
|
}
|
|
|
|
if (this.isFireproof() || this.world.isStatic) {
|
|
this.extinguish();
|
|
}
|
|
|
|
boolean flag = this instanceof EntityHuman && ((EntityHuman) this).abilities.isInvulnerable;
|
|
|
|
if (this.isAlive() && this.a(Material.WATER)) {
|
|
if (!this.aD() && !this.hasEffect(MobEffectList.WATER_BREATHING.id) && !flag) {
|
|
this.setAirTicks(this.j(this.getAirTicks()));
|
|
if (this.getAirTicks() == -20) {
|
|
this.setAirTicks(0);
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
float f = this.random.nextFloat() - this.random.nextFloat();
|
|
float f1 = this.random.nextFloat() - this.random.nextFloat();
|
|
float f2 = this.random.nextFloat() - this.random.nextFloat();
|
|
|
|
this.world.addParticle("bubble", this.locX + (double) f, this.locY + (double) f1, this.locZ + (double) f2, this.motX, this.motY, this.motZ);
|
|
}
|
|
|
|
this.damageEntity(DamageSource.DROWN, 2.0F);
|
|
}
|
|
}
|
|
|
|
if (!this.world.isStatic && this.al() && this.vehicle instanceof EntityLiving) {
|
|
this.mount((Entity) null);
|
|
}
|
|
} else {
|
|
// CraftBukkit start - Only set if needed to work around a DataWatcher inefficiency
|
|
if (this.getAirTicks() != 300) {
|
|
this.setAirTicks(maxAirTicks);
|
|
}
|
|
// CraftBukkit end
|
|
}
|
|
|
|
if (this.isAlive() && this.K()) {
|
|
this.extinguish();
|
|
}
|
|
|
|
this.aI = this.aJ;
|
|
if (this.attackTicks > 0) {
|
|
--this.attackTicks;
|
|
}
|
|
|
|
if (this.hurtTicks > 0) {
|
|
--this.hurtTicks;
|
|
}
|
|
|
|
if (this.noDamageTicks > 0 && !(this instanceof EntityPlayer)) {
|
|
--this.noDamageTicks;
|
|
}
|
|
|
|
if (this.getHealth() <= 0.0F) {
|
|
this.aE();
|
|
}
|
|
|
|
if (this.lastDamageByPlayerTime > 0) {
|
|
--this.lastDamageByPlayerTime;
|
|
} else {
|
|
this.killer = null;
|
|
}
|
|
|
|
if (this.bn != null && !this.bn.isAlive()) {
|
|
this.bn = null;
|
|
}
|
|
|
|
if (this.lastDamager != null) {
|
|
if (!this.lastDamager.isAlive()) {
|
|
this.b((EntityLiving) null);
|
|
} else if (this.ticksLived - this.bm > 100) {
|
|
this.b((EntityLiving) null);
|
|
}
|
|
}
|
|
|
|
this.aN();
|
|
this.aY = this.aX;
|
|
this.aN = this.aM;
|
|
this.aP = this.aO;
|
|
this.lastYaw = this.yaw;
|
|
this.lastPitch = this.pitch;
|
|
this.world.methodProfiler.b();
|
|
}
|
|
|
|
// CraftBukkit start
|
|
public int getExpReward() {
|
|
int exp = this.getExpValue(this.killer);
|
|
|
|
if (!this.world.isStatic && (this.lastDamageByPlayerTime > 0 || this.alwaysGivesExp()) && this.aF() && this.world.getGameRules().getBoolean("doMobLoot")) {
|
|
return exp;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
|
|
public boolean isBaby() {
|
|
return false;
|
|
}
|
|
|
|
protected void aE() {
|
|
++this.deathTicks;
|
|
if (this.deathTicks >= 20 && !this.dead) { // CraftBukkit - (this.deathTicks == 20) -> (this.deathTicks >= 20 && !this.dead)
|
|
int i;
|
|
|
|
// CraftBukkit start - Update getExpReward() above if the removed if() changes!
|
|
i = this.expToDrop;
|
|
while (i > 0) {
|
|
int j = EntityExperienceOrb.getOrbValue(i);
|
|
|
|
i -= j;
|
|
this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j));
|
|
}
|
|
this.expToDrop = 0;
|
|
// CraftBukkit end
|
|
|
|
this.die();
|
|
|
|
for (i = 0; i < 20; ++i) {
|
|
double d0 = this.random.nextGaussian() * 0.02D;
|
|
double d1 = this.random.nextGaussian() * 0.02D;
|
|
double d2 = this.random.nextGaussian() * 0.02D;
|
|
|
|
this.world.addParticle("explode", this.locX + (double) (this.random.nextFloat() * this.width * 2.0F) - (double) this.width, this.locY + (double) (this.random.nextFloat() * this.length), this.locZ + (double) (this.random.nextFloat() * this.width * 2.0F) - (double) this.width, d0, d1, d2);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected boolean aF() {
|
|
return !this.isBaby();
|
|
}
|
|
|
|
protected int j(int i) {
|
|
int j = EnchantmentManager.getOxygenEnchantmentLevel(this);
|
|
|
|
return j > 0 && this.random.nextInt(j + 1) > 0 ? i : i - 1;
|
|
}
|
|
|
|
protected int getExpValue(EntityHuman entityhuman) {
|
|
return 0;
|
|
}
|
|
|
|
protected boolean alwaysGivesExp() {
|
|
return false;
|
|
}
|
|
|
|
public Random aH() {
|
|
return this.random;
|
|
}
|
|
|
|
public EntityLiving getLastDamager() {
|
|
return this.lastDamager;
|
|
}
|
|
|
|
public int aJ() {
|
|
return this.bm;
|
|
}
|
|
|
|
public void b(EntityLiving entityliving) {
|
|
this.lastDamager = entityliving;
|
|
this.bm = this.ticksLived;
|
|
}
|
|
|
|
public EntityLiving aK() {
|
|
return this.bn;
|
|
}
|
|
|
|
public int aL() {
|
|
return this.bo;
|
|
}
|
|
|
|
public void l(Entity entity) {
|
|
if (entity instanceof EntityLiving) {
|
|
this.bn = (EntityLiving) entity;
|
|
} else {
|
|
this.bn = null;
|
|
}
|
|
|
|
this.bo = this.ticksLived;
|
|
}
|
|
|
|
public int aM() {
|
|
return this.aU;
|
|
}
|
|
|
|
public void b(NBTTagCompound nbttagcompound) {
|
|
nbttagcompound.setFloat("HealF", this.getHealth());
|
|
nbttagcompound.setShort("Health", (short) ((int) Math.ceil((double) this.getHealth())));
|
|
nbttagcompound.setShort("HurtTime", (short) this.hurtTicks);
|
|
nbttagcompound.setShort("DeathTime", (short) this.deathTicks);
|
|
nbttagcompound.setShort("AttackTime", (short) this.attackTicks);
|
|
nbttagcompound.setFloat("AbsorptionAmount", this.br());
|
|
ItemStack[] aitemstack = this.getEquipment();
|
|
int i = aitemstack.length;
|
|
|
|
int j;
|
|
ItemStack itemstack;
|
|
|
|
for (j = 0; j < i; ++j) {
|
|
itemstack = aitemstack[j];
|
|
if (itemstack != null) {
|
|
this.d.a(itemstack.D());
|
|
}
|
|
}
|
|
|
|
nbttagcompound.set("Attributes", GenericAttributes.a(this.bb()));
|
|
aitemstack = this.getEquipment();
|
|
i = aitemstack.length;
|
|
|
|
for (j = 0; j < i; ++j) {
|
|
itemstack = aitemstack[j];
|
|
if (itemstack != null) {
|
|
this.d.b(itemstack.D());
|
|
}
|
|
}
|
|
|
|
if (!this.effects.isEmpty()) {
|
|
NBTTagList nbttaglist = new NBTTagList();
|
|
Iterator iterator = this.effects.values().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
MobEffect mobeffect = (MobEffect) iterator.next();
|
|
|
|
nbttaglist.add(mobeffect.a(new NBTTagCompound()));
|
|
}
|
|
|
|
nbttagcompound.set("ActiveEffects", nbttaglist);
|
|
}
|
|
}
|
|
|
|
public void a(NBTTagCompound nbttagcompound) {
|
|
this.m(nbttagcompound.getFloat("AbsorptionAmount"));
|
|
if (nbttagcompound.hasKeyOfType("Attributes", 9) && this.world != null && !this.world.isStatic) {
|
|
GenericAttributes.a(this.bb(), nbttagcompound.getList("Attributes", 10));
|
|
}
|
|
|
|
if (nbttagcompound.hasKeyOfType("ActiveEffects", 9)) {
|
|
NBTTagList nbttaglist = nbttagcompound.getList("ActiveEffects", 10);
|
|
|
|
for (int i = 0; i < nbttaglist.size(); ++i) {
|
|
NBTTagCompound nbttagcompound1 = nbttaglist.get(i);
|
|
MobEffect mobeffect = MobEffect.b(nbttagcompound1);
|
|
|
|
if (mobeffect != null) {
|
|
this.effects.put(Integer.valueOf(mobeffect.getEffectId()), mobeffect);
|
|
}
|
|
}
|
|
}
|
|
|
|
// CraftBukkit start
|
|
if (nbttagcompound.hasKey("Bukkit.MaxHealth")) {
|
|
NBTBase nbtbase = nbttagcompound.get("Bukkit.MaxHealth");
|
|
if (nbtbase.getTypeId() == 5) {
|
|
this.getAttributeInstance(GenericAttributes.a).setValue((double) ((NBTTagFloat) nbtbase).c());
|
|
} else if (nbtbase.getTypeId() == 3) {
|
|
this.getAttributeInstance(GenericAttributes.a).setValue((double) ((NBTTagInt) nbtbase).d());
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
|
|
if (nbttagcompound.hasKeyOfType("HealF", 99)) {
|
|
this.setHealth(nbttagcompound.getFloat("HealF"));
|
|
} else {
|
|
NBTBase nbtbase = nbttagcompound.get("Health");
|
|
|
|
if (nbtbase == null) {
|
|
this.setHealth(this.getMaxHealth());
|
|
} else if (nbtbase.getTypeId() == 5) {
|
|
this.setHealth(((NBTTagFloat) nbtbase).h());
|
|
} else if (nbtbase.getTypeId() == 2) {
|
|
this.setHealth((float) ((NBTTagShort) nbtbase).e());
|
|
}
|
|
}
|
|
|
|
this.hurtTicks = nbttagcompound.getShort("HurtTime");
|
|
this.deathTicks = nbttagcompound.getShort("DeathTime");
|
|
this.attackTicks = nbttagcompound.getShort("AttackTime");
|
|
}
|
|
|
|
protected void aN() {
|
|
Iterator iterator = this.effects.keySet().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
Integer integer = (Integer) iterator.next();
|
|
MobEffect mobeffect = (MobEffect) this.effects.get(integer);
|
|
|
|
if (!mobeffect.tick(this)) {
|
|
if (!this.world.isStatic) {
|
|
iterator.remove();
|
|
this.b(mobeffect);
|
|
}
|
|
} else if (mobeffect.getDuration() % 600 == 0) {
|
|
this.a(mobeffect, false);
|
|
}
|
|
}
|
|
|
|
int i;
|
|
|
|
if (this.updateEffects) {
|
|
if (!this.world.isStatic) {
|
|
if (this.effects.isEmpty()) {
|
|
this.datawatcher.watch(8, Byte.valueOf((byte) 0));
|
|
this.datawatcher.watch(7, Integer.valueOf(0));
|
|
this.setInvisible(false);
|
|
} else {
|
|
i = PotionBrewer.a(this.effects.values());
|
|
this.datawatcher.watch(8, Byte.valueOf((byte) (PotionBrewer.b(this.effects.values()) ? 1 : 0)));
|
|
this.datawatcher.watch(7, Integer.valueOf(i));
|
|
this.setInvisible(this.hasEffect(MobEffectList.INVISIBILITY.id));
|
|
}
|
|
}
|
|
|
|
this.updateEffects = false;
|
|
}
|
|
|
|
i = this.datawatcher.getInt(7);
|
|
boolean flag = this.datawatcher.getByte(8) > 0;
|
|
|
|
if (i > 0) {
|
|
boolean flag1 = false;
|
|
|
|
if (!this.isInvisible()) {
|
|
flag1 = this.random.nextBoolean();
|
|
} else {
|
|
flag1 = this.random.nextInt(15) == 0;
|
|
}
|
|
|
|
if (flag) {
|
|
flag1 &= this.random.nextInt(5) == 0;
|
|
}
|
|
|
|
if (flag1 && i > 0) {
|
|
double d0 = (double) (i >> 16 & 255) / 255.0D;
|
|
double d1 = (double) (i >> 8 & 255) / 255.0D;
|
|
double d2 = (double) (i >> 0 & 255) / 255.0D;
|
|
|
|
this.world.addParticle(flag ? "mobSpellAmbient" : "mobSpell", this.locX + (this.random.nextDouble() - 0.5D) * (double) this.width, this.locY + this.random.nextDouble() * (double) this.length - (double) this.height, this.locZ + (this.random.nextDouble() - 0.5D) * (double) this.width, d0, d1, d2);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void removeAllEffects() {
|
|
Iterator iterator = this.effects.keySet().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
Integer integer = (Integer) iterator.next();
|
|
MobEffect mobeffect = (MobEffect) this.effects.get(integer);
|
|
|
|
if (!this.world.isStatic) {
|
|
iterator.remove();
|
|
this.b(mobeffect);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Collection getEffects() {
|
|
return this.effects.values();
|
|
}
|
|
|
|
public boolean hasEffect(int i) {
|
|
// CraftBukkit - Add size check for efficiency
|
|
return this.effects.size() != 0 && this.effects.containsKey(Integer.valueOf(i));
|
|
}
|
|
|
|
public boolean hasEffect(MobEffectList mobeffectlist) {
|
|
// CraftBukkit - Add size check for efficiency
|
|
return this.effects.size() != 0 && this.effects.containsKey(Integer.valueOf(mobeffectlist.id));
|
|
}
|
|
|
|
public MobEffect getEffect(MobEffectList mobeffectlist) {
|
|
return (MobEffect) this.effects.get(Integer.valueOf(mobeffectlist.id));
|
|
}
|
|
|
|
public void addEffect(MobEffect mobeffect) {
|
|
if (this.d(mobeffect)) {
|
|
if (this.effects.containsKey(Integer.valueOf(mobeffect.getEffectId()))) {
|
|
((MobEffect) this.effects.get(Integer.valueOf(mobeffect.getEffectId()))).a(mobeffect);
|
|
this.a((MobEffect) this.effects.get(Integer.valueOf(mobeffect.getEffectId())), true);
|
|
} else {
|
|
this.effects.put(Integer.valueOf(mobeffect.getEffectId()), mobeffect);
|
|
this.a(mobeffect);
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean d(MobEffect mobeffect) {
|
|
if (this.getMonsterType() == EnumMonsterType.UNDEAD) {
|
|
int i = mobeffect.getEffectId();
|
|
|
|
if (i == MobEffectList.REGENERATION.id || i == MobEffectList.POISON.id) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public boolean aQ() {
|
|
return this.getMonsterType() == EnumMonsterType.UNDEAD;
|
|
}
|
|
|
|
public void removeEffect(int i) {
|
|
MobEffect mobeffect = (MobEffect) this.effects.remove(Integer.valueOf(i));
|
|
|
|
if (mobeffect != null) {
|
|
this.b(mobeffect);
|
|
}
|
|
}
|
|
|
|
protected void a(MobEffect mobeffect) {
|
|
this.updateEffects = true;
|
|
if (!this.world.isStatic) {
|
|
MobEffectList.byId[mobeffect.getEffectId()].b(this, this.bb(), mobeffect.getAmplifier());
|
|
}
|
|
}
|
|
|
|
protected void a(MobEffect mobeffect, boolean flag) {
|
|
this.updateEffects = true;
|
|
if (flag && !this.world.isStatic) {
|
|
MobEffectList.byId[mobeffect.getEffectId()].a(this, this.bb(), mobeffect.getAmplifier());
|
|
MobEffectList.byId[mobeffect.getEffectId()].b(this, this.bb(), mobeffect.getAmplifier());
|
|
}
|
|
}
|
|
|
|
protected void b(MobEffect mobeffect) {
|
|
this.updateEffects = true;
|
|
if (!this.world.isStatic) {
|
|
MobEffectList.byId[mobeffect.getEffectId()].a(this, this.bb(), mobeffect.getAmplifier());
|
|
}
|
|
}
|
|
|
|
// CraftBukkit start - Delegate so we can handle providing a reason for health being regained
|
|
public void heal(float f) {
|
|
heal(f, EntityRegainHealthEvent.RegainReason.CUSTOM);
|
|
}
|
|
|
|
public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) {
|
|
float f1 = this.getHealth();
|
|
|
|
if (f1 > 0.0F) {
|
|
EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason);
|
|
this.world.getServer().getPluginManager().callEvent(event);
|
|
|
|
if (!event.isCancelled()) {
|
|
this.setHealth((float) (this.getHealth() + event.getAmount()));
|
|
}
|
|
}
|
|
}
|
|
|
|
public final float getHealth() {
|
|
// CraftBukkit start - Use unscaled health
|
|
if (this instanceof EntityPlayer) {
|
|
return (float) ((EntityPlayer) this).getBukkitEntity().getHealth();
|
|
}
|
|
// CraftBukkit end
|
|
return this.datawatcher.getFloat(6);
|
|
}
|
|
|
|
public void setHealth(float f) {
|
|
// CraftBukkit start - Handle scaled health
|
|
if (this instanceof EntityPlayer) {
|
|
org.bukkit.craftbukkit.entity.CraftPlayer player = ((EntityPlayer) this).getBukkitEntity();
|
|
// Squeeze
|
|
if (f < 0.0F) {
|
|
player.setRealHealth(0.0D);
|
|
} else if (f > player.getMaxHealth()) {
|
|
player.setRealHealth(player.getMaxHealth());
|
|
} else {
|
|
player.setRealHealth(f);
|
|
}
|
|
|
|
this.datawatcher.watch(6, Float.valueOf(player.getScaledHealth()));
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
this.datawatcher.watch(6, Float.valueOf(MathHelper.a(f, 0.0F, this.getMaxHealth())));
|
|
}
|
|
|
|
public boolean damageEntity(DamageSource damagesource, float f) {
|
|
if (this.isInvulnerable()) {
|
|
return false;
|
|
} else if (this.world.isStatic) {
|
|
return false;
|
|
} else {
|
|
this.aU = 0;
|
|
if (this.getHealth() <= 0.0F) {
|
|
return false;
|
|
} else if (damagesource.o() && this.hasEffect(MobEffectList.FIRE_RESISTANCE)) {
|
|
return false;
|
|
} else {
|
|
if ((damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) && this.getEquipment(4) != null) {
|
|
this.getEquipment(4).damage((int) (f * 4.0F + this.random.nextFloat() * f * 2.0F), this);
|
|
f *= 0.75F;
|
|
}
|
|
|
|
this.aF = 1.5F;
|
|
boolean flag = true;
|
|
|
|
// CraftBukkit start
|
|
EntityDamageEvent event = CraftEventFactory.handleEntityDamageEvent(this, damagesource, f);
|
|
if (event != null) {
|
|
if (event.isCancelled()) {
|
|
return false;
|
|
}
|
|
f = (float) event.getDamage();
|
|
}
|
|
// CraftBukkit end
|
|
|
|
if ((float) this.noDamageTicks > (float) this.maxNoDamageTicks / 2.0F) {
|
|
if (f <= this.lastDamage) {
|
|
return false;
|
|
}
|
|
|
|
this.d(damagesource, f - this.lastDamage);
|
|
this.lastDamage = f;
|
|
flag = false;
|
|
} else {
|
|
this.lastDamage = f;
|
|
this.aw = this.getHealth();
|
|
this.noDamageTicks = this.maxNoDamageTicks;
|
|
this.d(damagesource, f);
|
|
this.hurtTicks = this.ay = 10;
|
|
}
|
|
|
|
this.az = 0.0F;
|
|
Entity entity = damagesource.getEntity();
|
|
|
|
if (entity != null) {
|
|
if (entity instanceof EntityLiving) {
|
|
this.b((EntityLiving) entity);
|
|
}
|
|
|
|
if (entity instanceof EntityHuman) {
|
|
this.lastDamageByPlayerTime = 100;
|
|
this.killer = (EntityHuman) entity;
|
|
} else if (entity instanceof EntityWolf) {
|
|
EntityWolf entitywolf = (EntityWolf) entity;
|
|
|
|
if (entitywolf.isTamed()) {
|
|
this.lastDamageByPlayerTime = 100;
|
|
this.killer = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag) {
|
|
this.world.broadcastEntityEffect(this, (byte) 2);
|
|
if (damagesource != DamageSource.DROWN) {
|
|
this.P();
|
|
}
|
|
|
|
if (entity != null) {
|
|
double d0 = entity.locX - this.locX;
|
|
|
|
double d1;
|
|
|
|
for (d1 = entity.locZ - this.locZ; d0 * d0 + d1 * d1 < 1.0E-4D; d1 = (Math.random() - Math.random()) * 0.01D) {
|
|
d0 = (Math.random() - Math.random()) * 0.01D;
|
|
}
|
|
|
|
this.az = (float) (Math.atan2(d1, d0) * 180.0D / 3.1415927410125732D) - this.yaw;
|
|
this.a(entity, f, d0, d1);
|
|
} else {
|
|
this.az = (float) ((int) (Math.random() * 2.0D) * 180);
|
|
}
|
|
}
|
|
|
|
String s;
|
|
|
|
if (this.getHealth() <= 0.0F) {
|
|
s = this.aT();
|
|
if (flag && s != null) {
|
|
this.makeSound(s, this.be(), this.bf());
|
|
}
|
|
|
|
this.die(damagesource);
|
|
} else {
|
|
s = this.aS();
|
|
if (flag && s != null) {
|
|
this.makeSound(s, this.be(), this.bf());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void a(ItemStack itemstack) {
|
|
this.makeSound("random.break", 0.8F, 0.8F + this.world.random.nextFloat() * 0.4F);
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
Vec3D vec3d = Vec3D.a(((double) this.random.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D);
|
|
|
|
vec3d.a(-this.pitch * 3.1415927F / 180.0F);
|
|
vec3d.b(-this.yaw * 3.1415927F / 180.0F);
|
|
Vec3D vec3d1 = Vec3D.a(((double) this.random.nextFloat() - 0.5D) * 0.3D, (double) (-this.random.nextFloat()) * 0.6D - 0.3D, 0.6D);
|
|
|
|
vec3d1.a(-this.pitch * 3.1415927F / 180.0F);
|
|
vec3d1.b(-this.yaw * 3.1415927F / 180.0F);
|
|
vec3d1 = vec3d1.add(this.locX, this.locY + (double) this.getHeadHeight(), this.locZ);
|
|
this.world.addParticle("iconcrack_" + Item.b(itemstack.getItem()), vec3d1.a, vec3d1.b, vec3d1.c, vec3d.a, vec3d.b + 0.05D, vec3d.c);
|
|
}
|
|
}
|
|
|
|
public void die(DamageSource damagesource) {
|
|
Entity entity = damagesource.getEntity();
|
|
EntityLiving entityliving = this.aW();
|
|
|
|
if (this.ba >= 0 && entityliving != null) {
|
|
entityliving.b(this, this.ba);
|
|
}
|
|
|
|
if (entity != null) {
|
|
entity.a(this);
|
|
}
|
|
|
|
this.aT = true;
|
|
this.aV().g();
|
|
if (!this.world.isStatic) {
|
|
int i = 0;
|
|
|
|
if (entity instanceof EntityHuman) {
|
|
i = EnchantmentManager.getBonusMonsterLootEnchantmentLevel((EntityLiving) entity);
|
|
}
|
|
|
|
if (this.aF() && this.world.getGameRules().getBoolean("doMobLoot")) {
|
|
this.drops = new ArrayList<org.bukkit.inventory.ItemStack>(); // CraftBukkit - Setup drop capture
|
|
|
|
this.dropDeathLoot(this.lastDamageByPlayerTime > 0, i);
|
|
this.dropEquipment(this.lastDamageByPlayerTime > 0, i);
|
|
if (this.lastDamageByPlayerTime > 0) {
|
|
int j = this.random.nextInt(200) - i;
|
|
|
|
if (j < 5) {
|
|
this.getRareDrop(j <= 0 ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
// CraftBukkit start - Call death event
|
|
CraftEventFactory.callEntityDeathEvent(this, this.drops);
|
|
this.drops = null;
|
|
} else {
|
|
CraftEventFactory.callEntityDeathEvent(this);
|
|
// CraftBukkit end
|
|
}
|
|
}
|
|
|
|
this.world.broadcastEntityEffect(this, (byte) 3);
|
|
}
|
|
|
|
protected void dropEquipment(boolean flag, int i) {}
|
|
|
|
public void a(Entity entity, float f, double d0, double d1) {
|
|
if (this.random.nextDouble() >= this.getAttributeInstance(GenericAttributes.c).getValue()) {
|
|
this.al = true;
|
|
float f1 = MathHelper.sqrt(d0 * d0 + d1 * d1);
|
|
float f2 = 0.4F;
|
|
|
|
this.motX /= 2.0D;
|
|
this.motY /= 2.0D;
|
|
this.motZ /= 2.0D;
|
|
this.motX -= d0 / (double) f1 * (double) f2;
|
|
this.motY += (double) f2;
|
|
this.motZ -= d1 / (double) f1 * (double) f2;
|
|
if (this.motY > 0.4000000059604645D) {
|
|
this.motY = 0.4000000059604645D;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected String aS() {
|
|
return "game.neutral.hurt";
|
|
}
|
|
|
|
protected String aT() {
|
|
return "game.neutral.die";
|
|
}
|
|
|
|
protected void getRareDrop(int i) {}
|
|
|
|
protected void dropDeathLoot(boolean flag, int i) {}
|
|
|
|
public boolean h_() {
|
|
int i = MathHelper.floor(this.locX);
|
|
int j = MathHelper.floor(this.boundingBox.b);
|
|
int k = MathHelper.floor(this.locZ);
|
|
Block block = this.world.getType(i, j, k);
|
|
|
|
return block == Blocks.LADDER || block == Blocks.VINE;
|
|
}
|
|
|
|
public boolean isAlive() {
|
|
return !this.dead && this.getHealth() > 0.0F;
|
|
}
|
|
|
|
protected void b(float f) {
|
|
super.b(f);
|
|
MobEffect mobeffect = this.getEffect(MobEffectList.JUMP);
|
|
float f1 = mobeffect != null ? (float) (mobeffect.getAmplifier() + 1) : 0.0F;
|
|
// CraftBukkit start
|
|
float i = MathHelper.f(f - 3.0F - f1);
|
|
|
|
if (i > 0) {
|
|
EntityDamageEvent event = CraftEventFactory.callEntityDamageEvent(null, this, EntityDamageEvent.DamageCause.FALL, i);
|
|
if (event.isCancelled()) {
|
|
return;
|
|
}
|
|
|
|
i = (float) event.getDamage();
|
|
if (i > 0) {
|
|
this.getBukkitEntity().setLastDamageCause(event);
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
|
|
if (i > 0) {
|
|
this.makeSound(this.o(org.bukkit.util.NumberConversions.ceil(i)), 1.0F, 1.0F); // CraftBukkit - ceil
|
|
this.damageEntity(DamageSource.FALL, (float) i);
|
|
int j = MathHelper.floor(this.locX);
|
|
int k = MathHelper.floor(this.locY - 0.20000000298023224D - (double) this.height);
|
|
int l = MathHelper.floor(this.locZ);
|
|
Block block = this.world.getType(j, k, l);
|
|
|
|
if (block.getMaterial() != Material.AIR) {
|
|
StepSound stepsound = block.stepSound;
|
|
|
|
this.makeSound(stepsound.getStepSound(), stepsound.getVolume1() * 0.5F, stepsound.getVolume2() * 0.75F);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected String o(int i) {
|
|
return i > 4 ? "game.neutral.hurt.fall.big" : "game.neutral.hurt.fall.small";
|
|
}
|
|
|
|
public int aU() {
|
|
int i = 0;
|
|
ItemStack[] aitemstack = this.getEquipment();
|
|
int j = aitemstack.length;
|
|
|
|
for (int k = 0; k < j; ++k) {
|
|
ItemStack itemstack = aitemstack[k];
|
|
|
|
if (itemstack != null && itemstack.getItem() instanceof ItemArmor) {
|
|
int l = ((ItemArmor) itemstack.getItem()).c;
|
|
|
|
i += l;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
protected void h(float f) {}
|
|
|
|
protected float b(DamageSource damagesource, float f) {
|
|
if (!damagesource.ignoresArmor()) {
|
|
int i = 25 - this.aU();
|
|
float f1 = f * (float) i;
|
|
|
|
this.h(f);
|
|
f = f1 / 25.0F;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
protected float c(DamageSource damagesource, float f) {
|
|
if (damagesource.h()) {
|
|
return f;
|
|
} else {
|
|
if (this instanceof EntityZombie) {
|
|
f = f;
|
|
}
|
|
|
|
int i;
|
|
int j;
|
|
float f1;
|
|
|
|
if (this.hasEffect(MobEffectList.RESISTANCE) && damagesource != DamageSource.OUT_OF_WORLD) {
|
|
i = (this.getEffect(MobEffectList.RESISTANCE).getAmplifier() + 1) * 5;
|
|
j = 25 - i;
|
|
f1 = f * (float) j;
|
|
f = f1 / 25.0F;
|
|
}
|
|
|
|
if (f <= 0.0F) {
|
|
return 0.0F;
|
|
} else {
|
|
i = EnchantmentManager.a(this.getEquipment(), damagesource);
|
|
if (i > 20) {
|
|
i = 20;
|
|
}
|
|
|
|
if (i > 0 && i <= 20) {
|
|
j = 25 - i;
|
|
f1 = f * (float) j;
|
|
f = f1 / 25.0F;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void d(DamageSource damagesource, float f) {
|
|
if (!this.isInvulnerable()) {
|
|
f = this.b(damagesource, f);
|
|
f = this.c(damagesource, f);
|
|
float f1 = f;
|
|
|
|
f = Math.max(f - this.br(), 0.0F);
|
|
this.m(this.br() - (f1 - f));
|
|
if (f != 0.0F) {
|
|
float f2 = this.getHealth();
|
|
|
|
this.setHealth(f2 - f);
|
|
this.aV().a(damagesource, f2, f);
|
|
this.m(this.br() - f);
|
|
}
|
|
}
|
|
}
|
|
|
|
public CombatTracker aV() {
|
|
return this.combatTracker;
|
|
}
|
|
|
|
public EntityLiving aW() {
|
|
return (EntityLiving) (this.combatTracker.c() != null ? this.combatTracker.c() : (this.killer != null ? this.killer : (this.lastDamager != null ? this.lastDamager : null)));
|
|
}
|
|
|
|
public final float getMaxHealth() {
|
|
return (float) this.getAttributeInstance(GenericAttributes.a).getValue();
|
|
}
|
|
|
|
public final int aY() {
|
|
return this.datawatcher.getByte(9);
|
|
}
|
|
|
|
public final void p(int i) {
|
|
this.datawatcher.watch(9, Byte.valueOf((byte) i));
|
|
}
|
|
|
|
private int j() {
|
|
return this.hasEffect(MobEffectList.FASTER_DIG) ? 6 - (1 + this.getEffect(MobEffectList.FASTER_DIG).getAmplifier()) * 1 : (this.hasEffect(MobEffectList.SLOWER_DIG) ? 6 + (1 + this.getEffect(MobEffectList.SLOWER_DIG).getAmplifier()) * 2 : 6);
|
|
}
|
|
|
|
public void aZ() {
|
|
if (!this.at || this.au >= this.j() / 2 || this.au < 0) {
|
|
this.au = -1;
|
|
this.at = true;
|
|
if (this.world instanceof WorldServer) {
|
|
((WorldServer) this.world).getTracker().a((Entity) this, (Packet) (new PacketPlayOutAnimation(this, 0)));
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void F() {
|
|
this.damageEntity(DamageSource.OUT_OF_WORLD, 4.0F);
|
|
}
|
|
|
|
protected void ba() {
|
|
int i = this.j();
|
|
|
|
if (this.at) {
|
|
++this.au;
|
|
if (this.au >= i) {
|
|
this.au = 0;
|
|
this.at = false;
|
|
}
|
|
} else {
|
|
this.au = 0;
|
|
}
|
|
|
|
this.aD = (float) this.au / (float) i;
|
|
}
|
|
|
|
public AttributeInstance getAttributeInstance(IAttribute iattribute) {
|
|
return this.bb().a(iattribute);
|
|
}
|
|
|
|
public AttributeMapBase bb() {
|
|
if (this.d == null) {
|
|
this.d = new AttributeMapServer();
|
|
}
|
|
|
|
return this.d;
|
|
}
|
|
|
|
public EnumMonsterType getMonsterType() {
|
|
return EnumMonsterType.UNDEFINED;
|
|
}
|
|
|
|
public abstract ItemStack bd();
|
|
|
|
public abstract ItemStack getEquipment(int i);
|
|
|
|
public abstract void setEquipment(int i, ItemStack itemstack);
|
|
|
|
public void setSprinting(boolean flag) {
|
|
super.setSprinting(flag);
|
|
AttributeInstance attributeinstance = this.getAttributeInstance(GenericAttributes.d);
|
|
|
|
if (attributeinstance.a(b) != null) {
|
|
attributeinstance.b(c);
|
|
}
|
|
|
|
if (flag) {
|
|
attributeinstance.a(c);
|
|
}
|
|
}
|
|
|
|
public abstract ItemStack[] getEquipment();
|
|
|
|
protected float be() {
|
|
return 1.0F;
|
|
}
|
|
|
|
protected float bf() {
|
|
return this.isBaby() ? (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.5F : (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F;
|
|
}
|
|
|
|
protected boolean bg() {
|
|
return this.getHealth() <= 0.0F;
|
|
}
|
|
|
|
public void enderTeleportTo(double d0, double d1, double d2) {
|
|
this.setPositionRotation(d0, d1, d2, this.yaw, this.pitch);
|
|
}
|
|
|
|
public void m(Entity entity) {
|
|
double d0 = entity.locX;
|
|
double d1 = entity.boundingBox.b + (double) entity.length;
|
|
double d2 = entity.locZ;
|
|
byte b0 = 1;
|
|
|
|
for (int i = -b0; i <= b0; ++i) {
|
|
for (int j = -b0; j < b0; ++j) {
|
|
if (i != 0 || j != 0) {
|
|
int k = (int) (this.locX + (double) i);
|
|
int l = (int) (this.locZ + (double) j);
|
|
AxisAlignedBB axisalignedbb = this.boundingBox.c((double) i, 1.0D, (double) j);
|
|
|
|
if (this.world.a(axisalignedbb).isEmpty()) {
|
|
if (World.a((IBlockAccess) this.world, k, (int) this.locY, l)) {
|
|
this.enderTeleportTo(this.locX + (double) i, this.locY + 1.0D, this.locZ + (double) j);
|
|
return;
|
|
}
|
|
|
|
if (World.a((IBlockAccess) this.world, k, (int) this.locY - 1, l) || this.world.getType(k, (int) this.locY - 1, l).getMaterial() == Material.WATER) {
|
|
d0 = this.locX + (double) i;
|
|
d1 = this.locY + 1.0D;
|
|
d2 = this.locZ + (double) j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.enderTeleportTo(d0, d1, d2);
|
|
}
|
|
|
|
protected void bi() {
|
|
this.motY = 0.41999998688697815D;
|
|
if (this.hasEffect(MobEffectList.JUMP)) {
|
|
this.motY += (double) ((float) (this.getEffect(MobEffectList.JUMP).getAmplifier() + 1) * 0.1F);
|
|
}
|
|
|
|
if (this.isSprinting()) {
|
|
float f = this.yaw * 0.017453292F;
|
|
|
|
this.motX -= (double) (MathHelper.sin(f) * 0.2F);
|
|
this.motZ += (double) (MathHelper.cos(f) * 0.2F);
|
|
}
|
|
|
|
this.al = true;
|
|
}
|
|
|
|
public void e(float f, float f1) {
|
|
double d0;
|
|
|
|
if (this.L() && (!(this instanceof EntityHuman) || !((EntityHuman) this).abilities.isFlying)) {
|
|
d0 = this.locY;
|
|
this.a(f, f1, this.bj() ? 0.04F : 0.02F);
|
|
this.move(this.motX, this.motY, this.motZ);
|
|
this.motX *= 0.800000011920929D;
|
|
this.motY *= 0.800000011920929D;
|
|
this.motZ *= 0.800000011920929D;
|
|
this.motY -= 0.02D;
|
|
if (this.positionChanged && this.c(this.motX, this.motY + 0.6000000238418579D - this.locY + d0, this.motZ)) {
|
|
this.motY = 0.30000001192092896D;
|
|
}
|
|
} else if (this.O() && (!(this instanceof EntityHuman) || !((EntityHuman) this).abilities.isFlying)) {
|
|
d0 = this.locY;
|
|
this.a(f, f1, 0.02F);
|
|
this.move(this.motX, this.motY, this.motZ);
|
|
this.motX *= 0.5D;
|
|
this.motY *= 0.5D;
|
|
this.motZ *= 0.5D;
|
|
this.motY -= 0.02D;
|
|
if (this.positionChanged && this.c(this.motX, this.motY + 0.6000000238418579D - this.locY + d0, this.motZ)) {
|
|
this.motY = 0.30000001192092896D;
|
|
}
|
|
} else {
|
|
float f2 = 0.91F;
|
|
|
|
if (this.onGround) {
|
|
f2 = this.world.getType(MathHelper.floor(this.locX), MathHelper.floor(this.boundingBox.b) - 1, MathHelper.floor(this.locZ)).frictionFactor * 0.91F;
|
|
}
|
|
|
|
float f3 = 0.16277136F / (f2 * f2 * f2);
|
|
float f4;
|
|
|
|
if (this.onGround) {
|
|
f4 = this.bk() * f3;
|
|
} else {
|
|
f4 = this.aQ;
|
|
}
|
|
|
|
this.a(f, f1, f4);
|
|
f2 = 0.91F;
|
|
if (this.onGround) {
|
|
f2 = this.world.getType(MathHelper.floor(this.locX), MathHelper.floor(this.boundingBox.b) - 1, MathHelper.floor(this.locZ)).frictionFactor * 0.91F;
|
|
}
|
|
|
|
if (this.h_()) {
|
|
float f5 = 0.15F;
|
|
|
|
if (this.motX < (double) (-f5)) {
|
|
this.motX = (double) (-f5);
|
|
}
|
|
|
|
if (this.motX > (double) f5) {
|
|
this.motX = (double) f5;
|
|
}
|
|
|
|
if (this.motZ < (double) (-f5)) {
|
|
this.motZ = (double) (-f5);
|
|
}
|
|
|
|
if (this.motZ > (double) f5) {
|
|
this.motZ = (double) f5;
|
|
}
|
|
|
|
this.fallDistance = 0.0F;
|
|
if (this.motY < -0.15D) {
|
|
this.motY = -0.15D;
|
|
}
|
|
|
|
boolean flag = this.isSneaking() && this instanceof EntityHuman;
|
|
|
|
if (flag && this.motY < 0.0D) {
|
|
this.motY = 0.0D;
|
|
}
|
|
}
|
|
|
|
this.move(this.motX, this.motY, this.motZ);
|
|
if (this.positionChanged && this.h_()) {
|
|
this.motY = 0.2D;
|
|
}
|
|
|
|
if (this.world.isStatic && (!this.world.isLoaded((int) this.locX, 0, (int) this.locZ) || !this.world.getChunkAtWorldCoords((int) this.locX, (int) this.locZ).d)) {
|
|
if (this.locY > 0.0D) {
|
|
this.motY = -0.1D;
|
|
} else {
|
|
this.motY = 0.0D;
|
|
}
|
|
} else {
|
|
this.motY -= 0.08D;
|
|
}
|
|
|
|
this.motY *= 0.9800000190734863D;
|
|
this.motX *= (double) f2;
|
|
this.motZ *= (double) f2;
|
|
}
|
|
|
|
this.aE = this.aF;
|
|
d0 = this.locX - this.lastX;
|
|
double d1 = this.locZ - this.lastZ;
|
|
float f6 = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F;
|
|
|
|
if (f6 > 1.0F) {
|
|
f6 = 1.0F;
|
|
}
|
|
|
|
this.aF += (f6 - this.aF) * 0.4F;
|
|
this.aG += this.aF;
|
|
}
|
|
|
|
protected boolean bj() {
|
|
return false;
|
|
}
|
|
|
|
public float bk() {
|
|
return this.bj() ? this.bp : 0.1F;
|
|
}
|
|
|
|
public void i(float f) {
|
|
this.bp = f;
|
|
}
|
|
|
|
public boolean n(Entity entity) {
|
|
this.l(entity);
|
|
return false;
|
|
}
|
|
|
|
public boolean isSleeping() {
|
|
return false;
|
|
}
|
|
|
|
public void h() {
|
|
super.h();
|
|
if (!this.world.isStatic) {
|
|
int i = this.aY();
|
|
|
|
if (i > 0) {
|
|
if (this.av <= 0) {
|
|
this.av = 20 * (30 - i);
|
|
}
|
|
|
|
--this.av;
|
|
if (this.av <= 0) {
|
|
this.p(i - 1);
|
|
}
|
|
}
|
|
|
|
for (int j = 0; j < 5; ++j) {
|
|
ItemStack itemstack = this.g[j];
|
|
ItemStack itemstack1 = this.getEquipment(j);
|
|
|
|
if (!ItemStack.matches(itemstack1, itemstack)) {
|
|
((WorldServer) this.world).getTracker().a((Entity) this, (Packet) (new PacketPlayOutEntityEquipment(this.getId(), j, itemstack1)));
|
|
if (itemstack != null) {
|
|
this.d.a(itemstack.D());
|
|
}
|
|
|
|
if (itemstack1 != null) {
|
|
this.d.b(itemstack1.D());
|
|
}
|
|
|
|
this.g[j] = itemstack1 == null ? null : itemstack1.cloneItemStack();
|
|
}
|
|
}
|
|
|
|
if (this.ticksLived % 20 == 0) {
|
|
this.aV().g();
|
|
}
|
|
}
|
|
|
|
this.e();
|
|
double d0 = this.locX - this.lastX;
|
|
double d1 = this.locZ - this.lastZ;
|
|
float f = (float) (d0 * d0 + d1 * d1);
|
|
float f1 = this.aM;
|
|
float f2 = 0.0F;
|
|
|
|
this.aV = this.aW;
|
|
float f3 = 0.0F;
|
|
|
|
if (f > 0.0025000002F) {
|
|
f3 = 1.0F;
|
|
f2 = (float) Math.sqrt((double) f) * 3.0F;
|
|
// CraftBukkit - Math -> TrigMath
|
|
f1 = (float) org.bukkit.craftbukkit.TrigMath.atan2(d1, d0) * 180.0F / 3.1415927F - 90.0F;
|
|
}
|
|
|
|
if (this.aD > 0.0F) {
|
|
f1 = this.yaw;
|
|
}
|
|
|
|
if (!this.onGround) {
|
|
f3 = 0.0F;
|
|
}
|
|
|
|
this.aW += (f3 - this.aW) * 0.3F;
|
|
this.world.methodProfiler.a("headTurn");
|
|
f2 = this.f(f1, f2);
|
|
this.world.methodProfiler.b();
|
|
this.world.methodProfiler.a("rangeChecks");
|
|
|
|
while (this.yaw - this.lastYaw < -180.0F) {
|
|
this.lastYaw -= 360.0F;
|
|
}
|
|
|
|
while (this.yaw - this.lastYaw >= 180.0F) {
|
|
this.lastYaw += 360.0F;
|
|
}
|
|
|
|
while (this.aM - this.aN < -180.0F) {
|
|
this.aN -= 360.0F;
|
|
}
|
|
|
|
while (this.aM - this.aN >= 180.0F) {
|
|
this.aN += 360.0F;
|
|
}
|
|
|
|
while (this.pitch - this.lastPitch < -180.0F) {
|
|
this.lastPitch -= 360.0F;
|
|
}
|
|
|
|
while (this.pitch - this.lastPitch >= 180.0F) {
|
|
this.lastPitch += 360.0F;
|
|
}
|
|
|
|
while (this.aO - this.aP < -180.0F) {
|
|
this.aP -= 360.0F;
|
|
}
|
|
|
|
while (this.aO - this.aP >= 180.0F) {
|
|
this.aP += 360.0F;
|
|
}
|
|
|
|
this.world.methodProfiler.b();
|
|
this.aX += f2;
|
|
}
|
|
|
|
protected float f(float f, float f1) {
|
|
float f2 = MathHelper.g(f - this.aM);
|
|
|
|
this.aM += f2 * 0.3F;
|
|
float f3 = MathHelper.g(this.yaw - this.aM);
|
|
boolean flag = f3 < -90.0F || f3 >= 90.0F;
|
|
|
|
if (f3 < -75.0F) {
|
|
f3 = -75.0F;
|
|
}
|
|
|
|
if (f3 >= 75.0F) {
|
|
f3 = 75.0F;
|
|
}
|
|
|
|
this.aM = this.yaw - f3;
|
|
if (f3 * f3 > 2500.0F) {
|
|
this.aM += f3 * 0.2F;
|
|
}
|
|
|
|
if (flag) {
|
|
f1 *= -1.0F;
|
|
}
|
|
|
|
return f1;
|
|
}
|
|
|
|
public void e() {
|
|
if (this.bq > 0) {
|
|
--this.bq;
|
|
}
|
|
|
|
if (this.bg > 0) {
|
|
double d0 = this.locX + (this.bh - this.locX) / (double) this.bg;
|
|
double d1 = this.locY + (this.bi - this.locY) / (double) this.bg;
|
|
double d2 = this.locZ + (this.bj - this.locZ) / (double) this.bg;
|
|
double d3 = MathHelper.g(this.bk - (double) this.yaw);
|
|
|
|
this.yaw = (float) ((double) this.yaw + d3 / (double) this.bg);
|
|
this.pitch = (float) ((double) this.pitch + (this.bl - (double) this.pitch) / (double) this.bg);
|
|
--this.bg;
|
|
this.setPosition(d0, d1, d2);
|
|
this.b(this.yaw, this.pitch);
|
|
} else if (!this.bq()) {
|
|
this.motX *= 0.98D;
|
|
this.motY *= 0.98D;
|
|
this.motZ *= 0.98D;
|
|
}
|
|
|
|
if (Math.abs(this.motX) < 0.005D) {
|
|
this.motX = 0.0D;
|
|
}
|
|
|
|
if (Math.abs(this.motY) < 0.005D) {
|
|
this.motY = 0.0D;
|
|
}
|
|
|
|
if (Math.abs(this.motZ) < 0.005D) {
|
|
this.motZ = 0.0D;
|
|
}
|
|
|
|
this.world.methodProfiler.a("ai");
|
|
if (this.bg()) {
|
|
this.bc = false;
|
|
this.bd = 0.0F;
|
|
this.be = 0.0F;
|
|
this.bf = 0.0F;
|
|
} else if (this.bq()) {
|
|
if (this.bj()) {
|
|
this.world.methodProfiler.a("newAi");
|
|
this.bm();
|
|
this.world.methodProfiler.b();
|
|
} else {
|
|
this.world.methodProfiler.a("oldAi");
|
|
this.bp();
|
|
this.world.methodProfiler.b();
|
|
this.aO = this.yaw;
|
|
}
|
|
}
|
|
|
|
this.world.methodProfiler.b();
|
|
this.world.methodProfiler.a("jump");
|
|
if (this.bc) {
|
|
if (!this.L() && !this.O()) {
|
|
if (this.onGround && this.bq == 0) {
|
|
this.bi();
|
|
this.bq = 10;
|
|
}
|
|
} else {
|
|
this.motY += 0.03999999910593033D;
|
|
}
|
|
} else {
|
|
this.bq = 0;
|
|
}
|
|
|
|
this.world.methodProfiler.b();
|
|
this.world.methodProfiler.a("travel");
|
|
this.bd *= 0.98F;
|
|
this.be *= 0.98F;
|
|
this.bf *= 0.9F;
|
|
this.e(this.bd, this.be);
|
|
this.world.methodProfiler.b();
|
|
this.world.methodProfiler.a("push");
|
|
if (!this.world.isStatic) {
|
|
this.bn();
|
|
}
|
|
|
|
this.world.methodProfiler.b();
|
|
}
|
|
|
|
protected void bm() {}
|
|
|
|
protected void bn() {
|
|
List list = this.world.getEntities(this, this.boundingBox.grow(0.20000000298023224D, 0.0D, 0.20000000298023224D));
|
|
|
|
if (list != null && !list.isEmpty()) {
|
|
for (int i = 0; i < list.size(); ++i) {
|
|
Entity entity = (Entity) list.get(i);
|
|
|
|
// TODO better check now?
|
|
// CraftBukkit start - Only handle mob (non-player) collisions every other tick
|
|
if (entity instanceof EntityLiving && !(this instanceof EntityPlayer) && this.ticksLived % 2 == 0) {
|
|
continue;
|
|
}
|
|
// CraftBukkit end
|
|
|
|
if (entity.R()) {
|
|
this.o(entity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void o(Entity entity) {
|
|
entity.collide(this);
|
|
}
|
|
|
|
public void aa() {
|
|
super.aa();
|
|
this.aV = this.aW;
|
|
this.aW = 0.0F;
|
|
this.fallDistance = 0.0F;
|
|
}
|
|
|
|
protected void bo() {}
|
|
|
|
protected void bp() {
|
|
++this.aU;
|
|
}
|
|
|
|
public void f(boolean flag) {
|
|
this.bc = flag;
|
|
}
|
|
|
|
public void receive(Entity entity, int i) {
|
|
if (!entity.dead && !this.world.isStatic) {
|
|
EntityTracker entitytracker = ((WorldServer) this.world).getTracker();
|
|
|
|
if (entity instanceof EntityItem) {
|
|
entitytracker.a(entity, (Packet) (new PacketPlayOutCollect(entity.getId(), this.getId())));
|
|
}
|
|
|
|
if (entity instanceof EntityArrow) {
|
|
entitytracker.a(entity, (Packet) (new PacketPlayOutCollect(entity.getId(), this.getId())));
|
|
}
|
|
|
|
if (entity instanceof EntityExperienceOrb) {
|
|
entitytracker.a(entity, (Packet) (new PacketPlayOutCollect(entity.getId(), this.getId())));
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean p(Entity entity) {
|
|
return this.world.a(Vec3D.a(this.locX, this.locY + (double) this.getHeadHeight(), this.locZ), Vec3D.a(entity.locX, entity.locY + (double) entity.getHeadHeight(), entity.locZ)) == null;
|
|
}
|
|
|
|
public Vec3D af() {
|
|
return this.j(1.0F);
|
|
}
|
|
|
|
public Vec3D j(float f) {
|
|
float f1;
|
|
float f2;
|
|
float f3;
|
|
float f4;
|
|
|
|
if (f == 1.0F) {
|
|
f1 = MathHelper.cos(-this.yaw * 0.017453292F - 3.1415927F);
|
|
f2 = MathHelper.sin(-this.yaw * 0.017453292F - 3.1415927F);
|
|
f3 = -MathHelper.cos(-this.pitch * 0.017453292F);
|
|
f4 = MathHelper.sin(-this.pitch * 0.017453292F);
|
|
return Vec3D.a((double) (f2 * f3), (double) f4, (double) (f1 * f3));
|
|
} else {
|
|
f1 = this.lastPitch + (this.pitch - this.lastPitch) * f;
|
|
f2 = this.lastYaw + (this.yaw - this.lastYaw) * f;
|
|
f3 = MathHelper.cos(-f2 * 0.017453292F - 3.1415927F);
|
|
f4 = MathHelper.sin(-f2 * 0.017453292F - 3.1415927F);
|
|
float f5 = -MathHelper.cos(-f1 * 0.017453292F);
|
|
float f6 = MathHelper.sin(-f1 * 0.017453292F);
|
|
|
|
return Vec3D.a((double) (f4 * f5), (double) f6, (double) (f3 * f5));
|
|
}
|
|
}
|
|
|
|
public boolean bq() {
|
|
return !this.world.isStatic;
|
|
}
|
|
|
|
public boolean Q() {
|
|
return !this.dead;
|
|
}
|
|
|
|
public boolean R() {
|
|
return !this.dead;
|
|
}
|
|
|
|
public float getHeadHeight() {
|
|
return this.length * 0.85F;
|
|
}
|
|
|
|
protected void P() {
|
|
this.velocityChanged = this.random.nextDouble() >= this.getAttributeInstance(GenericAttributes.c).getValue();
|
|
}
|
|
|
|
public float getHeadRotation() {
|
|
return this.aO;
|
|
}
|
|
|
|
public float br() {
|
|
return this.br;
|
|
}
|
|
|
|
public void m(float f) {
|
|
if (f < 0.0F) {
|
|
f = 0.0F;
|
|
}
|
|
|
|
this.br = f;
|
|
}
|
|
|
|
public ScoreboardTeamBase getScoreboardTeam() {
|
|
return null;
|
|
}
|
|
|
|
public boolean c(EntityLiving entityliving) {
|
|
return this.a(entityliving.getScoreboardTeam());
|
|
}
|
|
|
|
public boolean a(ScoreboardTeamBase scoreboardteambase) {
|
|
return this.getScoreboardTeam() != null ? this.getScoreboardTeam().isAlly(scoreboardteambase) : false;
|
|
}
|
|
|
|
public void bt() {}
|
|
|
|
public void bu() {}
|
|
}
|