001package net.minecraft.entity;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import java.util.Collection;
006import java.util.HashMap;
007import java.util.Iterator;
008import java.util.List;
009import java.util.Random;
010import net.minecraft.block.Block;
011import net.minecraft.block.StepSound;
012import net.minecraft.block.material.Material;
013import net.minecraft.enchantment.EnchantmentHelper;
014import net.minecraft.entity.ai.EntityAITasks;
015import net.minecraft.entity.ai.EntityJumpHelper;
016import net.minecraft.entity.ai.EntityLookHelper;
017import net.minecraft.entity.ai.EntityMoveHelper;
018import net.minecraft.entity.ai.EntitySenses;
019import net.minecraft.entity.item.EntityItem;
020import net.minecraft.entity.item.EntityXPOrb;
021import net.minecraft.entity.monster.EntityCreeper;
022import net.minecraft.entity.monster.EntityGhast;
023import net.minecraft.entity.passive.EntityPig;
024import net.minecraft.entity.passive.EntityWolf;
025import net.minecraft.entity.player.EntityPlayer;
026import net.minecraft.entity.projectile.EntityArrow;
027import net.minecraft.item.Item;
028import net.minecraft.item.ItemArmor;
029import net.minecraft.item.ItemStack;
030import net.minecraft.item.ItemSword;
031import net.minecraft.nbt.NBTTagCompound;
032import net.minecraft.nbt.NBTTagFloat;
033import net.minecraft.nbt.NBTTagList;
034import net.minecraft.network.packet.Packet18Animation;
035import net.minecraft.network.packet.Packet22Collect;
036import net.minecraft.network.packet.Packet5PlayerInventory;
037import net.minecraft.pathfinding.PathNavigate;
038import net.minecraft.potion.Potion;
039import net.minecraft.potion.PotionEffect;
040import net.minecraft.potion.PotionHelper;
041import net.minecraft.util.ChunkCoordinates;
042import net.minecraft.util.DamageSource;
043import net.minecraft.util.MathHelper;
044import net.minecraft.util.MovingObjectPosition;
045import net.minecraft.util.Vec3;
046import net.minecraft.world.World;
047import net.minecraft.world.WorldServer;
048
049import net.minecraftforge.common.ForgeHooks;
050import net.minecraftforge.common.MinecraftForge;
051import net.minecraftforge.event.entity.living.*;
052import static net.minecraftforge.event.entity.living.LivingEvent.*;
053
054public abstract class EntityLiving extends Entity
055{
056    /**
057     * An array of probabilities that determines whether a random enchantment should be added to the held item. Indexed
058     * by difficulty.
059     */
060    private static final float[] enchantmentProbability = new float[] {0.0F, 0.0F, 0.05F, 0.1F};
061
062    /** Probability to get enchanted armor */
063    private static final float[] armorEnchantmentProbability = new float[] {0.0F, 0.0F, 0.05F, 0.2F};
064
065    /** Probability to get armor */
066    private static final float[] armorProbability = new float[] {0.0F, 0.0F, 0.05F, 0.02F};
067
068    /** Probability to pick up loot */
069    public static final float[] pickUpLootProability = new float[] {0.0F, 0.1F, 0.15F, 0.45F};
070    public int maxHurtResistantTime = 20;
071    public float field_70769_ao;
072    public float field_70770_ap;
073    public float renderYawOffset = 0.0F;
074    public float prevRenderYawOffset = 0.0F;
075
076    /** Entity head rotation yaw */
077    public float rotationYawHead = 0.0F;
078
079    /** Entity head rotation yaw at previous tick */
080    public float prevRotationYawHead = 0.0F;
081    protected float field_70768_au;
082    protected float field_70766_av;
083    protected float field_70764_aw;
084    protected float field_70763_ax;
085    protected boolean field_70753_ay = true;
086
087    /** the path for the texture of this entityLiving */
088    protected String texture = "/mob/char.png";
089    protected boolean field_70740_aA = true;
090    protected float field_70741_aB = 0.0F;
091
092    /**
093     * a string holding the type of entity it is currently only implemented in entityPlayer(as 'humanoid')
094     */
095    protected String entityType = null;
096    protected float field_70743_aD = 1.0F;
097
098    /** The score value of the Mob, the amount of points the mob is worth. */
099    protected int scoreValue = 0;
100    protected float field_70745_aF = 0.0F;
101
102    /**
103     * A factor used to determine how far this entity will move each tick if it is walking on land. Adjusted by speed,
104     * and slipperiness of the current block.
105     */
106    public float landMovementFactor = 0.1F;
107
108    /**
109     * A factor used to determine how far this entity will move each tick if it is jumping or falling.
110     */
111    public float jumpMovementFactor = 0.02F;
112    public float prevSwingProgress;
113    public float swingProgress;
114    protected int health = this.getMaxHealth();
115    public int prevHealth;
116
117    /**
118     * in each step in the damage calculations, this is set to the 'carryover' that would result if someone was damaged
119     * .25 hearts (for example), and added to the damage in the next step
120     */
121    public int carryoverDamage;
122
123    /** Number of ticks since this EntityLiving last produced its sound */
124    public int livingSoundTime;
125
126    /**
127     * The amount of time remaining this entity should act 'hurt'. (Visual appearance of red tint)
128     */
129    public int hurtTime;
130
131    /** What the hurt time was max set to last. */
132    public int maxHurtTime;
133
134    /** The yaw at which this entity was last attacked from. */
135    public float attackedAtYaw = 0.0F;
136
137    /**
138     * The amount of time remaining this entity should act 'dead', i.e. have a corpse in the world.
139     */
140    public int deathTime = 0;
141    public int attackTime = 0;
142    public float prevCameraPitch;
143    public float cameraPitch;
144
145    /**
146     * This gets set on entity death, but never used. Looks like a duplicate of isDead
147     */
148    protected boolean dead = false;
149
150    /** The experience points the Entity gives. */
151    public int experienceValue;
152    public int field_70731_aW = -1;
153    public float field_70730_aX = (float)(Math.random() * 0.8999999761581421D + 0.10000000149011612D);
154    public float prevLegYaw;
155    public float legYaw;
156
157    /**
158     * Only relevant when legYaw is not 0(the entity is moving). Influences where in its swing legs and arms currently
159     * are.
160     */
161    public float legSwing;
162
163    /** The most recent player that has attacked this entity */
164    protected EntityPlayer attackingPlayer = null;
165
166    /**
167     * Set to 60 when hit by the player or the player's wolf, then decrements. Used to determine whether the entity
168     * should drop items on death.
169     */
170    protected int recentlyHit = 0;
171
172    /** is only being set, has no uses as of MC 1.1 */
173    private EntityLiving entityLivingToAttack = null;
174    private int revengeTimer = 0;
175    private EntityLiving lastAttackingEntity = null;
176    public int arrowHitTimer = 0;
177    protected HashMap activePotionsMap = new HashMap();
178
179    /** Whether the DataWatcher needs to be updated with the active potions */
180    private boolean potionsNeedUpdate = true;
181    private int field_70748_f;
182    private EntityLookHelper lookHelper;
183    private EntityMoveHelper moveHelper;
184
185    /** Entity jumping helper */
186    private EntityJumpHelper jumpHelper;
187    private EntityBodyHelper bodyHelper;
188    private PathNavigate navigator;
189    public final EntityAITasks tasks;
190    protected final EntityAITasks targetTasks;
191
192    /** The active target the Task system uses for tracking */
193    private EntityLiving attackTarget;
194    private EntitySenses senses;
195    private float AIMoveSpeed;
196    private ChunkCoordinates homePosition = new ChunkCoordinates(0, 0, 0);
197
198    /** If -1 there is no maximum distance */
199    private float maximumHomeDistance = -1.0F;
200
201    /** Equipment (armor and held item) for this entity. */
202    private ItemStack[] equipment = new ItemStack[5];
203
204    /** Chances for each equipment piece from dropping when this entity dies. */
205    protected float[] equipmentDropChances = new float[5];
206    private ItemStack[] field_82180_bT = new ItemStack[5];
207
208    /** Whether an arm swing is currently in progress. */
209    public boolean isSwingInProgress = false;
210    public int swingProgressInt = 0;
211
212    /** Whether this entity can pick up items from the ground. */
213    protected boolean canPickUpLoot = false;
214
215    /** Whether this entity should NOT despawn. */
216    private boolean persistenceRequired = false;
217
218    /**
219     * The number of updates over which the new position and rotation are to be applied to the entity.
220     */
221    protected int newPosRotationIncrements;
222
223    /** The new X position to be applied to the entity. */
224    protected double newPosX;
225
226    /** The new Y position to be applied to the entity. */
227    protected double newPosY;
228
229    /** The new Z position to be applied to the entity. */
230    protected double newPosZ;
231
232    /** The new yaw rotation to be applied to the entity. */
233    protected double newRotationYaw;
234
235    /** The new yaw rotation to be applied to the entity. */
236    protected double newRotationPitch;
237    float field_70706_bo = 0.0F;
238
239    /** Amount of damage taken in last hit, in half-hearts */
240    protected int lastDamage = 0;
241
242    /** Holds the living entity age, used to control the despawn. */
243    protected int entityAge = 0;
244    protected float moveStrafing;
245    protected float moveForward;
246    protected float randomYawVelocity;
247
248    /** used to check whether entity is jumping. */
249    public boolean isJumping = false;
250    protected float defaultPitch = 0.0F;
251    protected float moveSpeed = 0.7F;
252
253    /** Number of ticks since last jump */
254    private int jumpTicks = 0;
255
256    /** This entity's current target. */
257    private Entity currentTarget;
258
259    /** How long to keep a specific target entity */
260    protected int numTicksToChaseTarget = 0;
261
262    public EntityLiving(World par1World)
263    {
264        super(par1World);
265        this.preventEntitySpawning = true;
266        this.tasks = new EntityAITasks(par1World != null && par1World.theProfiler != null ? par1World.theProfiler : null);
267        this.targetTasks = new EntityAITasks(par1World != null && par1World.theProfiler != null ? par1World.theProfiler : null);
268        this.lookHelper = new EntityLookHelper(this);
269        this.moveHelper = new EntityMoveHelper(this);
270        this.jumpHelper = new EntityJumpHelper(this);
271        this.bodyHelper = new EntityBodyHelper(this);
272        this.navigator = new PathNavigate(this, par1World, 16.0F);
273        this.senses = new EntitySenses(this);
274        this.field_70770_ap = (float)(Math.random() + 1.0D) * 0.01F;
275        this.setPosition(this.posX, this.posY, this.posZ);
276        this.field_70769_ao = (float)Math.random() * 12398.0F;
277        this.rotationYaw = (float)(Math.random() * Math.PI * 2.0D);
278        this.rotationYawHead = this.rotationYaw;
279
280        for (int var2 = 0; var2 < this.equipmentDropChances.length; ++var2)
281        {
282            this.equipmentDropChances[var2] = 0.05F;
283        }
284
285        this.stepHeight = 0.5F;
286    }
287
288    public EntityLookHelper getLookHelper()
289    {
290        return this.lookHelper;
291    }
292
293    public EntityMoveHelper getMoveHelper()
294    {
295        return this.moveHelper;
296    }
297
298    public EntityJumpHelper getJumpHelper()
299    {
300        return this.jumpHelper;
301    }
302
303    public PathNavigate getNavigator()
304    {
305        return this.navigator;
306    }
307
308    /**
309     * returns the EntitySenses Object for the EntityLiving
310     */
311    public EntitySenses getEntitySenses()
312    {
313        return this.senses;
314    }
315
316    public Random getRNG()
317    {
318        return this.rand;
319    }
320
321    public EntityLiving getAITarget()
322    {
323        return this.entityLivingToAttack;
324    }
325
326    public EntityLiving getLastAttackingEntity()
327    {
328        return this.lastAttackingEntity;
329    }
330
331    public void setLastAttackingEntity(Entity par1Entity)
332    {
333        if (par1Entity instanceof EntityLiving)
334        {
335            this.lastAttackingEntity = (EntityLiving)par1Entity;
336        }
337    }
338
339    public int getAge()
340    {
341        return this.entityAge;
342    }
343
344    public float setRotationYawHead()
345    {
346        return this.rotationYawHead;
347    }
348
349    @SideOnly(Side.CLIENT)
350
351    /**
352     * Sets the head's yaw rotation of the entity.
353     */
354    public void setHeadRotationYaw(float par1)
355    {
356        this.rotationYawHead = par1;
357    }
358
359    /**
360     * the movespeed used for the new AI system
361     */
362    public float getAIMoveSpeed()
363    {
364        return this.AIMoveSpeed;
365    }
366
367    /**
368     * set the movespeed used for the new AI system
369     */
370    public void setAIMoveSpeed(float par1)
371    {
372        this.AIMoveSpeed = par1;
373        this.setMoveForward(par1);
374    }
375
376    public boolean attackEntityAsMob(Entity par1Entity)
377    {
378        this.setLastAttackingEntity(par1Entity);
379        return false;
380    }
381
382    /**
383     * Gets the active target the Task system uses for tracking
384     */
385    public EntityLiving getAttackTarget()
386    {
387        return this.attackTarget;
388    }
389
390    /**
391     * Sets the active target the Task system uses for tracking
392     */
393    public void setAttackTarget(EntityLiving par1EntityLiving)
394    {
395        this.attackTarget = par1EntityLiving;
396        ForgeHooks.onLivingSetAttackTarget(this, par1EntityLiving);
397    }
398
399    /**
400     * Returns true if this entity can attack entities of the specified class.
401     */
402    public boolean canAttackClass(Class par1Class)
403    {
404        return EntityCreeper.class != par1Class && EntityGhast.class != par1Class;
405    }
406
407    /**
408     * This function applies the benefits of growing back wool and faster growing up to the acting entity. (This
409     * function is used in the AIEatGrass)
410     */
411    public void eatGrassBonus() {}
412
413    /**
414     * Takes in the distance the entity has fallen this tick and whether its on the ground to update the fall distance
415     * and deal fall damage if landing on the ground.  Args: distanceFallenThisTick, onGround
416     */
417    protected void updateFallState(double par1, boolean par3)
418    {
419        if (!this.isInWater())
420        {
421            this.handleWaterMovement();
422        }
423
424        if (par3 && this.fallDistance > 0.0F)
425        {
426            int var4 = MathHelper.floor_double(this.posX);
427            int var5 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset);
428            int var6 = MathHelper.floor_double(this.posZ);
429            int var7 = this.worldObj.getBlockId(var4, var5, var6);
430
431            if (var7 == 0)
432            {
433                int var8 = this.worldObj.blockGetRenderType(var4, var5 - 1, var6);
434
435                if (var8 == 11 || var8 == 32 || var8 == 21)
436                {
437                    var7 = this.worldObj.getBlockId(var4, var5 - 1, var6);
438                }
439            }
440
441            if (var7 > 0)
442            {
443                Block.blocksList[var7].onFallenUpon(this.worldObj, var4, var5, var6, this, this.fallDistance);
444            }
445        }
446
447        super.updateFallState(par1, par3);
448    }
449
450    /**
451     * Returns true if entity is within home distance from current position
452     */
453    public boolean isWithinHomeDistanceCurrentPosition()
454    {
455        return this.isWithinHomeDistance(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ));
456    }
457
458    public boolean isWithinHomeDistance(int par1, int par2, int par3)
459    {
460        return this.maximumHomeDistance == -1.0F ? true : this.homePosition.getDistanceSquared(par1, par2, par3) < this.maximumHomeDistance * this.maximumHomeDistance;
461    }
462
463    public void setHomeArea(int par1, int par2, int par3, int par4)
464    {
465        this.homePosition.set(par1, par2, par3);
466        this.maximumHomeDistance = (float)par4;
467    }
468
469    public ChunkCoordinates getHomePosition()
470    {
471        return this.homePosition;
472    }
473
474    public float getMaximumHomeDistance()
475    {
476        return this.maximumHomeDistance;
477    }
478
479    public void detachHome()
480    {
481        this.maximumHomeDistance = -1.0F;
482    }
483
484    public boolean hasHome()
485    {
486        return this.maximumHomeDistance != -1.0F;
487    }
488
489    public void setRevengeTarget(EntityLiving par1EntityLiving)
490    {
491        this.entityLivingToAttack = par1EntityLiving;
492        this.revengeTimer = this.entityLivingToAttack != null ? 60 : 0;
493        ForgeHooks.onLivingSetAttackTarget(this, par1EntityLiving);
494    }
495
496    protected void entityInit()
497    {
498        this.dataWatcher.addObject(8, Integer.valueOf(this.field_70748_f));
499        this.dataWatcher.addObject(9, Byte.valueOf((byte)0));
500        this.dataWatcher.addObject(10, Byte.valueOf((byte)0));
501    }
502
503    /**
504     * returns true if the entity provided in the argument can be seen. (Raytrace)
505     */
506    public boolean canEntityBeSeen(Entity par1Entity)
507    {
508        return this.worldObj.rayTraceBlocks(this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ), this.worldObj.getWorldVec3Pool().getVecFromPool(par1Entity.posX, par1Entity.posY + (double)par1Entity.getEyeHeight(), par1Entity.posZ)) == null;
509    }
510
511    @SideOnly(Side.CLIENT)
512
513    /**
514     * Returns the texture's file path as a String.
515     */
516    public String getTexture()
517    {
518        return this.texture;
519    }
520
521    /**
522     * Returns true if other Entities should be prevented from moving through this Entity.
523     */
524    public boolean canBeCollidedWith()
525    {
526        return !this.isDead;
527    }
528
529    /**
530     * Returns true if this entity should push and be pushed by other entities when colliding.
531     */
532    public boolean canBePushed()
533    {
534        return !this.isDead;
535    }
536
537    public float getEyeHeight()
538    {
539        return this.height * 0.85F;
540    }
541
542    /**
543     * Get number of ticks, at least during which the living entity will be silent.
544     */
545    public int getTalkInterval()
546    {
547        return 80;
548    }
549
550    /**
551     * Plays living's sound at its position
552     */
553    public void playLivingSound()
554    {
555        String var1 = this.getLivingSound();
556
557        if (var1 != null)
558        {
559            this.playSound(var1, this.getSoundVolume(), this.getSoundPitch());
560        }
561    }
562
563    /**
564     * Gets called every tick from main Entity class
565     */
566    public void onEntityUpdate()
567    {
568        this.prevSwingProgress = this.swingProgress;
569        super.onEntityUpdate();
570        this.worldObj.theProfiler.startSection("mobBaseTick");
571
572        if (this.isEntityAlive() && this.rand.nextInt(1000) < this.livingSoundTime++)
573        {
574            this.livingSoundTime = -this.getTalkInterval();
575            this.playLivingSound();
576        }
577
578        if (this.isEntityAlive() && this.isEntityInsideOpaqueBlock())
579        {
580            this.attackEntityFrom(DamageSource.inWall, 1);
581        }
582
583        if (this.isImmuneToFire() || this.worldObj.isRemote)
584        {
585            this.extinguish();
586        }
587
588        boolean var1 = this instanceof EntityPlayer && ((EntityPlayer)this).capabilities.disableDamage;
589
590        if (this.isEntityAlive() && this.isInsideOfMaterial(Material.water) && !this.canBreatheUnderwater() && !this.activePotionsMap.containsKey(Integer.valueOf(Potion.waterBreathing.id)) && !var1)
591        {
592            this.setAir(this.decreaseAirSupply(this.getAir()));
593
594            if (this.getAir() == -20)
595            {
596                this.setAir(0);
597
598                for (int var2 = 0; var2 < 8; ++var2)
599                {
600                    float var3 = this.rand.nextFloat() - this.rand.nextFloat();
601                    float var4 = this.rand.nextFloat() - this.rand.nextFloat();
602                    float var5 = this.rand.nextFloat() - this.rand.nextFloat();
603                    this.worldObj.spawnParticle("bubble", this.posX + (double)var3, this.posY + (double)var4, this.posZ + (double)var5, this.motionX, this.motionY, this.motionZ);
604                }
605
606                this.attackEntityFrom(DamageSource.drown, 2);
607            }
608
609            this.extinguish();
610        }
611        else
612        {
613            this.setAir(300);
614        }
615
616        this.prevCameraPitch = this.cameraPitch;
617
618        if (this.attackTime > 0)
619        {
620            --this.attackTime;
621        }
622
623        if (this.hurtTime > 0)
624        {
625            --this.hurtTime;
626        }
627
628        if (this.hurtResistantTime > 0)
629        {
630            --this.hurtResistantTime;
631        }
632
633        if (this.health <= 0)
634        {
635            this.onDeathUpdate();
636        }
637
638        if (this.recentlyHit > 0)
639        {
640            --this.recentlyHit;
641        }
642        else
643        {
644            this.attackingPlayer = null;
645        }
646
647        if (this.lastAttackingEntity != null && !this.lastAttackingEntity.isEntityAlive())
648        {
649            this.lastAttackingEntity = null;
650        }
651
652        if (this.entityLivingToAttack != null)
653        {
654            if (!this.entityLivingToAttack.isEntityAlive())
655            {
656                this.setRevengeTarget((EntityLiving)null);
657            }
658            else if (this.revengeTimer > 0)
659            {
660                --this.revengeTimer;
661            }
662            else
663            {
664                this.setRevengeTarget((EntityLiving)null);
665            }
666        }
667
668        this.updatePotionEffects();
669        this.field_70763_ax = this.field_70764_aw;
670        this.prevRenderYawOffset = this.renderYawOffset;
671        this.prevRotationYawHead = this.rotationYawHead;
672        this.prevRotationYaw = this.rotationYaw;
673        this.prevRotationPitch = this.rotationPitch;
674        this.worldObj.theProfiler.endSection();
675    }
676
677    /**
678     * handles entity death timer, experience orb and particle creation
679     */
680    protected void onDeathUpdate()
681    {
682        ++this.deathTime;
683
684        if (this.deathTime == 20)
685        {
686            int var1;
687
688            if (!this.worldObj.isRemote && (this.recentlyHit > 0 || this.isPlayer()) && !this.isChild())
689            {
690                var1 = this.getExperiencePoints(this.attackingPlayer);
691
692                while (var1 > 0)
693                {
694                    int var2 = EntityXPOrb.getXPSplit(var1);
695                    var1 -= var2;
696                    this.worldObj.spawnEntityInWorld(new EntityXPOrb(this.worldObj, this.posX, this.posY, this.posZ, var2));
697                }
698            }
699
700            this.setDead();
701
702            for (var1 = 0; var1 < 20; ++var1)
703            {
704                double var8 = this.rand.nextGaussian() * 0.02D;
705                double var4 = this.rand.nextGaussian() * 0.02D;
706                double var6 = this.rand.nextGaussian() * 0.02D;
707                this.worldObj.spawnParticle("explode", this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, var8, var4, var6);
708            }
709        }
710    }
711
712    /**
713     * Decrements the entity's air supply when underwater
714     */
715    protected int decreaseAirSupply(int par1)
716    {
717        int var2 = EnchantmentHelper.getRespiration(this);
718        return var2 > 0 && this.rand.nextInt(var2 + 1) > 0 ? par1 : par1 - 1;
719    }
720
721    /**
722     * Get the experience points the entity currently has.
723     */
724    protected int getExperiencePoints(EntityPlayer par1EntityPlayer)
725    {
726        if (this.experienceValue > 0)
727        {
728            int var2 = this.experienceValue;
729            ItemStack[] var3 = this.getLastActiveItems();
730
731            for (int var4 = 0; var4 < var3.length; ++var4)
732            {
733                if (var3[var4] != null && this.equipmentDropChances[var4] <= 1.0F)
734                {
735                    var2 += 1 + this.rand.nextInt(3);
736                }
737            }
738
739            return var2;
740        }
741        else
742        {
743            return this.experienceValue;
744        }
745    }
746
747    /**
748     * Only use is to identify if class is an instance of player for experience dropping
749     */
750    protected boolean isPlayer()
751    {
752        return false;
753    }
754
755    /**
756     * Spawns an explosion particle around the Entity's location
757     */
758    public void spawnExplosionParticle()
759    {
760        for (int var1 = 0; var1 < 20; ++var1)
761        {
762            double var2 = this.rand.nextGaussian() * 0.02D;
763            double var4 = this.rand.nextGaussian() * 0.02D;
764            double var6 = this.rand.nextGaussian() * 0.02D;
765            double var8 = 10.0D;
766            this.worldObj.spawnParticle("explode", this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width - var2 * var8, this.posY + (double)(this.rand.nextFloat() * this.height) - var4 * var8, this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width - var6 * var8, var2, var4, var6);
767        }
768    }
769
770    /**
771     * Handles updating while being ridden by an entity
772     */
773    public void updateRidden()
774    {
775        super.updateRidden();
776        this.field_70768_au = this.field_70766_av;
777        this.field_70766_av = 0.0F;
778        this.fallDistance = 0.0F;
779    }
780
781    @SideOnly(Side.CLIENT)
782
783    /**
784     * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX,
785     * posY, posZ, yaw, pitch
786     */
787    public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
788    {
789        this.yOffset = 0.0F;
790        this.newPosX = par1;
791        this.newPosY = par3;
792        this.newPosZ = par5;
793        this.newRotationYaw = (double)par7;
794        this.newRotationPitch = (double)par8;
795        this.newPosRotationIncrements = par9;
796    }
797
798    /**
799     * Called to update the entity's position/logic.
800     */
801    public void onUpdate()
802    {
803        if (ForgeHooks.onLivingUpdate(this))
804        {
805            return;
806        }
807
808        super.onUpdate();
809
810        if (!this.worldObj.isRemote)
811        {
812            int var1;
813
814            for (var1 = 0; var1 < 5; ++var1)
815            {
816                ItemStack var2 = this.getCurrentItemOrArmor(var1);
817
818                if (!ItemStack.areItemStacksEqual(var2, this.field_82180_bT[var1]))
819                {
820                    ((WorldServer)this.worldObj).getEntityTracker().sendPacketToAllPlayersTrackingEntity(this, new Packet5PlayerInventory(this.entityId, var1, var2));
821                    this.field_82180_bT[var1] = var2 == null ? null : var2.copy();
822                }
823            }
824
825            var1 = this.getArrowCountInEntity();
826
827            if (var1 > 0)
828            {
829                if (this.arrowHitTimer <= 0)
830                {
831                    this.arrowHitTimer = 20 * (30 - var1);
832                }
833
834                --this.arrowHitTimer;
835
836                if (this.arrowHitTimer <= 0)
837                {
838                    this.setArrowCountInEntity(var1 - 1);
839                }
840            }
841        }
842
843        this.onLivingUpdate();
844        double var12 = this.posX - this.prevPosX;
845        double var3 = this.posZ - this.prevPosZ;
846        float var5 = (float)(var12 * var12 + var3 * var3);
847        float var6 = this.renderYawOffset;
848        float var7 = 0.0F;
849        this.field_70768_au = this.field_70766_av;
850        float var8 = 0.0F;
851
852        if (var5 > 0.0025000002F)
853        {
854            var8 = 1.0F;
855            var7 = (float)Math.sqrt((double)var5) * 3.0F;
856            var6 = (float)Math.atan2(var3, var12) * 180.0F / (float)Math.PI - 90.0F;
857        }
858
859        if (this.swingProgress > 0.0F)
860        {
861            var6 = this.rotationYaw;
862        }
863
864        if (!this.onGround)
865        {
866            var8 = 0.0F;
867        }
868
869        this.field_70766_av += (var8 - this.field_70766_av) * 0.3F;
870        this.worldObj.theProfiler.startSection("headTurn");
871
872        if (this.isAIEnabled())
873        {
874            this.bodyHelper.func_75664_a();
875        }
876        else
877        {
878            float var9 = MathHelper.wrapAngleTo180_float(var6 - this.renderYawOffset);
879            this.renderYawOffset += var9 * 0.3F;
880            float var10 = MathHelper.wrapAngleTo180_float(this.rotationYaw - this.renderYawOffset);
881            boolean var11 = var10 < -90.0F || var10 >= 90.0F;
882
883            if (var10 < -75.0F)
884            {
885                var10 = -75.0F;
886            }
887
888            if (var10 >= 75.0F)
889            {
890                var10 = 75.0F;
891            }
892
893            this.renderYawOffset = this.rotationYaw - var10;
894
895            if (var10 * var10 > 2500.0F)
896            {
897                this.renderYawOffset += var10 * 0.2F;
898            }
899
900            if (var11)
901            {
902                var7 *= -1.0F;
903            }
904        }
905
906        this.worldObj.theProfiler.endSection();
907        this.worldObj.theProfiler.startSection("rangeChecks");
908
909        while (this.rotationYaw - this.prevRotationYaw < -180.0F)
910        {
911            this.prevRotationYaw -= 360.0F;
912        }
913
914        while (this.rotationYaw - this.prevRotationYaw >= 180.0F)
915        {
916            this.prevRotationYaw += 360.0F;
917        }
918
919        while (this.renderYawOffset - this.prevRenderYawOffset < -180.0F)
920        {
921            this.prevRenderYawOffset -= 360.0F;
922        }
923
924        while (this.renderYawOffset - this.prevRenderYawOffset >= 180.0F)
925        {
926            this.prevRenderYawOffset += 360.0F;
927        }
928
929        while (this.rotationPitch - this.prevRotationPitch < -180.0F)
930        {
931            this.prevRotationPitch -= 360.0F;
932        }
933
934        while (this.rotationPitch - this.prevRotationPitch >= 180.0F)
935        {
936            this.prevRotationPitch += 360.0F;
937        }
938
939        while (this.rotationYawHead - this.prevRotationYawHead < -180.0F)
940        {
941            this.prevRotationYawHead -= 360.0F;
942        }
943
944        while (this.rotationYawHead - this.prevRotationYawHead >= 180.0F)
945        {
946            this.prevRotationYawHead += 360.0F;
947        }
948
949        this.worldObj.theProfiler.endSection();
950        this.field_70764_aw += var7;
951    }
952
953    /**
954     * Heal living entity (param: amount of half-hearts)
955     */
956    public void heal(int par1)
957    {
958        if (this.health > 0)
959        {
960            this.health += par1;
961
962            if (this.health > this.getMaxHealth())
963            {
964                this.health = this.getMaxHealth();
965            }
966
967            this.hurtResistantTime = this.maxHurtResistantTime / 2;
968        }
969    }
970
971    public abstract int getMaxHealth();
972
973    public int getHealth()
974    {
975        return this.health;
976    }
977
978    public void setEntityHealth(int par1)
979    {
980        this.health = par1;
981
982        if (par1 > this.getMaxHealth())
983        {
984            par1 = this.getMaxHealth();
985        }
986    }
987
988    /**
989     * Called when the entity is attacked.
990     */
991    public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
992    {
993        if (ForgeHooks.onLivingAttack(this, par1DamageSource, par2))
994        {
995            return false;
996        }
997
998        if (this.isEntityInvulnerable())
999        {
1000            return false;
1001        }
1002        else if (this.worldObj.isRemote)
1003        {
1004            return false;
1005        }
1006        else
1007        {
1008            this.entityAge = 0;
1009
1010            if (this.health <= 0)
1011            {
1012                return false;
1013            }
1014            else if (par1DamageSource.isFireDamage() && this.isPotionActive(Potion.fireResistance))
1015            {
1016                return false;
1017            }
1018            else
1019            {
1020                if ((par1DamageSource == DamageSource.anvil || par1DamageSource == DamageSource.fallingBlock) && this.getCurrentItemOrArmor(4) != null)
1021                {
1022                    this.getCurrentItemOrArmor(4).damageItem(par2 * 4 + this.rand.nextInt(par2 * 2), this);
1023                    par2 = (int)((float)par2 * 0.75F);
1024                }
1025
1026                this.legYaw = 1.5F;
1027                boolean var3 = true;
1028
1029                if ((float)this.hurtResistantTime > (float)this.maxHurtResistantTime / 2.0F)
1030                {
1031                    if (par2 <= this.lastDamage)
1032                    {
1033                        return false;
1034                    }
1035
1036                    this.damageEntity(par1DamageSource, par2 - this.lastDamage);
1037                    this.lastDamage = par2;
1038                    var3 = false;
1039                }
1040                else
1041                {
1042                    this.lastDamage = par2;
1043                    this.prevHealth = this.health;
1044                    this.hurtResistantTime = this.maxHurtResistantTime;
1045                    this.damageEntity(par1DamageSource, par2);
1046                    this.hurtTime = this.maxHurtTime = 10;
1047                }
1048
1049                this.attackedAtYaw = 0.0F;
1050                Entity var4 = par1DamageSource.getEntity();
1051
1052                if (var4 != null)
1053                {
1054                    if (var4 instanceof EntityLiving)
1055                    {
1056                        this.setRevengeTarget((EntityLiving)var4);
1057                    }
1058
1059                    if (var4 instanceof EntityPlayer)
1060                    {
1061                        this.recentlyHit = 60;
1062                        this.attackingPlayer = (EntityPlayer)var4;
1063                    }
1064                    else if (var4 instanceof EntityWolf)
1065                    {
1066                        EntityWolf var5 = (EntityWolf)var4;
1067
1068                        if (var5.isTamed())
1069                        {
1070                            this.recentlyHit = 60;
1071                            this.attackingPlayer = null;
1072                        }
1073                    }
1074                }
1075
1076                if (var3)
1077                {
1078                    this.worldObj.setEntityState(this, (byte)2);
1079
1080                    if (par1DamageSource != DamageSource.drown && par1DamageSource != DamageSource.explosion2)
1081                    {
1082                        this.setBeenAttacked();
1083                    }
1084
1085                    if (var4 != null)
1086                    {
1087                        double var9 = var4.posX - this.posX;
1088                        double var7;
1089
1090                        for (var7 = var4.posZ - this.posZ; var9 * var9 + var7 * var7 < 1.0E-4D; var7 = (Math.random() - Math.random()) * 0.01D)
1091                        {
1092                            var9 = (Math.random() - Math.random()) * 0.01D;
1093                        }
1094
1095                        this.attackedAtYaw = (float)(Math.atan2(var7, var9) * 180.0D / Math.PI) - this.rotationYaw;
1096                        this.knockBack(var4, par2, var9, var7);
1097                    }
1098                    else
1099                    {
1100                        this.attackedAtYaw = (float)((int)(Math.random() * 2.0D) * 180);
1101                    }
1102                }
1103
1104                if (this.health <= 0)
1105                {
1106                    if (var3)
1107                    {
1108                        this.playSound(this.getDeathSound(), this.getSoundVolume(), this.getSoundPitch());
1109                    }
1110
1111                    this.onDeath(par1DamageSource);
1112                }
1113                else if (var3)
1114                {
1115                    this.playSound(this.getHurtSound(), this.getSoundVolume(), this.getSoundPitch());
1116                }
1117
1118                return true;
1119            }
1120        }
1121    }
1122
1123    /**
1124     * Gets the pitch of living sounds in living entities.
1125     */
1126    protected float getSoundPitch()
1127    {
1128        return this.isChild() ? (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.5F : (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F;
1129    }
1130
1131    @SideOnly(Side.CLIENT)
1132
1133    /**
1134     * Setups the entity to do the hurt animation. Only used by packets in multiplayer.
1135     */
1136    public void performHurtAnimation()
1137    {
1138        this.hurtTime = this.maxHurtTime = 10;
1139        this.attackedAtYaw = 0.0F;
1140    }
1141
1142    /**
1143     * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue
1144     */
1145    public int getTotalArmorValue()
1146    {
1147        int var1 = 0;
1148        ItemStack[] var2 = this.getLastActiveItems();
1149        int var3 = var2.length;
1150
1151        for (int var4 = 0; var4 < var3; ++var4)
1152        {
1153            ItemStack var5 = var2[var4];
1154
1155            if (var5 != null && var5.getItem() instanceof ItemArmor)
1156            {
1157                int var6 = ((ItemArmor)var5.getItem()).damageReduceAmount;
1158                var1 += var6;
1159            }
1160        }
1161
1162        return var1;
1163    }
1164
1165    protected void damageArmor(int par1) {}
1166
1167    /**
1168     * Reduces damage, depending on armor
1169     */
1170    protected int applyArmorCalculations(DamageSource par1DamageSource, int par2)
1171    {
1172        if (!par1DamageSource.isUnblockable())
1173        {
1174            int var3 = 25 - this.getTotalArmorValue();
1175            int var4 = par2 * var3 + this.carryoverDamage;
1176            this.damageArmor(par2);
1177            par2 = var4 / 25;
1178            this.carryoverDamage = var4 % 25;
1179        }
1180
1181        return par2;
1182    }
1183
1184    /**
1185     * Reduces damage, depending on potions
1186     */
1187    protected int applyPotionDamageCalculations(DamageSource par1DamageSource, int par2)
1188    {
1189        if (this.isPotionActive(Potion.resistance))
1190        {
1191            int var3 = (this.getActivePotionEffect(Potion.resistance).getAmplifier() + 1) * 5;
1192            int var4 = 25 - var3;
1193            int var5 = par2 * var4 + this.carryoverDamage;
1194            par2 = var5 / 25;
1195            this.carryoverDamage = var5 % 25;
1196        }
1197
1198        return par2;
1199    }
1200
1201    /**
1202     * Deals damage to the entity. If its a EntityPlayer then will take damage from the armor first and then health
1203     * second with the reduced value. Args: damageAmount
1204     */
1205    protected void damageEntity(DamageSource par1DamageSource, int par2)
1206    {
1207        if (!this.isEntityInvulnerable())
1208        {
1209            par2 = ForgeHooks.onLivingHurt(this, par1DamageSource, par2);
1210            if (par2 <= 0)
1211            {
1212                return;
1213            }
1214            par2 = this.applyArmorCalculations(par1DamageSource, par2);
1215            par2 = this.applyPotionDamageCalculations(par1DamageSource, par2);
1216            this.health -= par2;
1217        }
1218    }
1219
1220    /**
1221     * Returns the volume for the sounds this mob makes.
1222     */
1223    protected float getSoundVolume()
1224    {
1225        return 1.0F;
1226    }
1227
1228    /**
1229     * Returns the sound this mob makes while it's alive.
1230     */
1231    protected String getLivingSound()
1232    {
1233        return null;
1234    }
1235
1236    /**
1237     * Returns the sound this mob makes when it is hurt.
1238     */
1239    protected String getHurtSound()
1240    {
1241        return "damage.hit";
1242    }
1243
1244    /**
1245     * Returns the sound this mob makes on death.
1246     */
1247    protected String getDeathSound()
1248    {
1249        return "damage.hit";
1250    }
1251
1252    /**
1253     * knocks back this entity
1254     */
1255    public void knockBack(Entity par1Entity, int par2, double par3, double par5)
1256    {
1257        this.isAirBorne = true;
1258        float var7 = MathHelper.sqrt_double(par3 * par3 + par5 * par5);
1259        float var8 = 0.4F;
1260        this.motionX /= 2.0D;
1261        this.motionY /= 2.0D;
1262        this.motionZ /= 2.0D;
1263        this.motionX -= par3 / (double)var7 * (double)var8;
1264        this.motionY += (double)var8;
1265        this.motionZ -= par5 / (double)var7 * (double)var8;
1266
1267        if (this.motionY > 0.4000000059604645D)
1268        {
1269            this.motionY = 0.4000000059604645D;
1270        }
1271    }
1272
1273    /**
1274     * Called when the mob's health reaches 0.
1275     */
1276    public void onDeath(DamageSource par1DamageSource)
1277    {
1278        if (ForgeHooks.onLivingDeath(this, par1DamageSource))
1279        {
1280            return;
1281        }
1282
1283        Entity var2 = par1DamageSource.getEntity();
1284
1285        if (this.scoreValue >= 0 && var2 != null)
1286        {
1287            var2.addToPlayerScore(this, this.scoreValue);
1288        }
1289
1290        if (var2 != null)
1291        {
1292            var2.onKillEntity(this);
1293        }
1294
1295        this.dead = true;
1296
1297        if (!this.worldObj.isRemote)
1298        {
1299            int var3 = 0;
1300
1301            if (var2 instanceof EntityPlayer)
1302            {
1303                var3 = EnchantmentHelper.getLootingModifier((EntityLiving)var2);
1304            }
1305
1306            captureDrops = true;
1307            capturedDrops.clear();
1308            int var4 = 0;
1309
1310            if (!this.isChild() && this.worldObj.getGameRules().getGameRuleBooleanValue("doMobLoot"))
1311            {
1312                this.dropFewItems(this.recentlyHit > 0, var3);
1313                this.dropEquipment(this.recentlyHit > 0, var3);
1314
1315                if (this.recentlyHit > 0)
1316                {
1317                    var4 = this.rand.nextInt(200) - var3;
1318
1319                    if (var4 < 5)
1320                    {
1321                        this.dropRareDrop(var4 <= 0 ? 1 : 0);
1322                    }
1323                }
1324            }
1325
1326            captureDrops = false;
1327
1328            if (!ForgeHooks.onLivingDrops(this, par1DamageSource, capturedDrops, var3, recentlyHit > 0, var4))
1329            {
1330                for (EntityItem item : capturedDrops)
1331                {
1332                    worldObj.spawnEntityInWorld(item);
1333                }
1334            }
1335        }
1336
1337        this.worldObj.setEntityState(this, (byte)3);
1338    }
1339
1340    protected void dropRareDrop(int par1) {}
1341
1342    /**
1343     * Drop 0-2 items of this living's type. @param par1 - Whether this entity has recently been hit by a player. @param
1344     * par2 - Level of Looting used to kill this mob.
1345     */
1346    protected void dropFewItems(boolean par1, int par2)
1347    {
1348        int var3 = this.getDropItemId();
1349
1350        if (var3 > 0)
1351        {
1352            int var4 = this.rand.nextInt(3);
1353
1354            if (par2 > 0)
1355            {
1356                var4 += this.rand.nextInt(par2 + 1);
1357            }
1358
1359            for (int var5 = 0; var5 < var4; ++var5)
1360            {
1361                this.dropItem(var3, 1);
1362            }
1363        }
1364    }
1365
1366    /**
1367     * Returns the item ID for the item the mob drops on death.
1368     */
1369    protected int getDropItemId()
1370    {
1371        return 0;
1372    }
1373
1374    /**
1375     * Called when the mob is falling. Calculates and applies fall damage.
1376     */
1377    protected void fall(float par1)
1378    {
1379        par1 = ForgeHooks.onLivingFall(this, par1);
1380        if (par1 <= 0)
1381        {
1382            return;
1383        }
1384
1385        super.fall(par1);
1386        int var2 = MathHelper.ceiling_float_int(par1 - 3.0F);
1387
1388        if (var2 > 0)
1389        {
1390            if (var2 > 4)
1391            {
1392                this.playSound("damage.fallbig", 1.0F, 1.0F);
1393            }
1394            else
1395            {
1396                this.playSound("damage.fallsmall", 1.0F, 1.0F);
1397            }
1398
1399            this.attackEntityFrom(DamageSource.fall, var2);
1400            int var3 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset), MathHelper.floor_double(this.posZ));
1401
1402            if (var3 > 0)
1403            {
1404                StepSound var4 = Block.blocksList[var3].stepSound;
1405                this.playSound(var4.getStepSound(), var4.getVolume() * 0.5F, var4.getPitch() * 0.75F);
1406            }
1407        }
1408    }
1409
1410    /**
1411     * Moves the entity based on the specified heading.  Args: strafe, forward
1412     */
1413    public void moveEntityWithHeading(float par1, float par2)
1414    {
1415        double var9;
1416
1417        if (this.isInWater() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying))
1418        {
1419            var9 = this.posY;
1420            this.moveFlying(par1, par2, this.isAIEnabled() ? 0.04F : 0.02F);
1421            this.moveEntity(this.motionX, this.motionY, this.motionZ);
1422            this.motionX *= 0.800000011920929D;
1423            this.motionY *= 0.800000011920929D;
1424            this.motionZ *= 0.800000011920929D;
1425            this.motionY -= 0.02D;
1426
1427            if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ))
1428            {
1429                this.motionY = 0.30000001192092896D;
1430            }
1431        }
1432        else if (this.handleLavaMovement() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying))
1433        {
1434            var9 = this.posY;
1435            this.moveFlying(par1, par2, 0.02F);
1436            this.moveEntity(this.motionX, this.motionY, this.motionZ);
1437            this.motionX *= 0.5D;
1438            this.motionY *= 0.5D;
1439            this.motionZ *= 0.5D;
1440            this.motionY -= 0.02D;
1441
1442            if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ))
1443            {
1444                this.motionY = 0.30000001192092896D;
1445            }
1446        }
1447        else
1448        {
1449            float var3 = 0.91F;
1450
1451            if (this.onGround)
1452            {
1453                var3 = 0.54600006F;
1454                int var4 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ));
1455
1456                if (var4 > 0)
1457                {
1458                    var3 = Block.blocksList[var4].slipperiness * 0.91F;
1459                }
1460            }
1461
1462            float var8 = 0.16277136F / (var3 * var3 * var3);
1463            float var5;
1464
1465            if (this.onGround)
1466            {
1467                if (this.isAIEnabled())
1468                {
1469                    var5 = this.getAIMoveSpeed();
1470                }
1471                else
1472                {
1473                    var5 = this.landMovementFactor;
1474                }
1475
1476                var5 *= var8;
1477            }
1478            else
1479            {
1480                var5 = this.jumpMovementFactor;
1481            }
1482
1483            this.moveFlying(par1, par2, var5);
1484            var3 = 0.91F;
1485
1486            if (this.onGround)
1487            {
1488                var3 = 0.54600006F;
1489                int var6 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ));
1490
1491                if (var6 > 0)
1492                {
1493                    var3 = Block.blocksList[var6].slipperiness * 0.91F;
1494                }
1495            }
1496
1497            if (this.isOnLadder())
1498            {
1499                float var10 = 0.15F;
1500
1501                if (this.motionX < (double)(-var10))
1502                {
1503                    this.motionX = (double)(-var10);
1504                }
1505
1506                if (this.motionX > (double)var10)
1507                {
1508                    this.motionX = (double)var10;
1509                }
1510
1511                if (this.motionZ < (double)(-var10))
1512                {
1513                    this.motionZ = (double)(-var10);
1514                }
1515
1516                if (this.motionZ > (double)var10)
1517                {
1518                    this.motionZ = (double)var10;
1519                }
1520
1521                this.fallDistance = 0.0F;
1522
1523                if (this.motionY < -0.15D)
1524                {
1525                    this.motionY = -0.15D;
1526                }
1527
1528                boolean var7 = this.isSneaking() && this instanceof EntityPlayer;
1529
1530                if (var7 && this.motionY < 0.0D)
1531                {
1532                    this.motionY = 0.0D;
1533                }
1534            }
1535
1536            this.moveEntity(this.motionX, this.motionY, this.motionZ);
1537
1538            if (this.isCollidedHorizontally && this.isOnLadder())
1539            {
1540                this.motionY = 0.2D;
1541            }
1542
1543            if (this.worldObj.isRemote && (!this.worldObj.blockExists((int)this.posX, 0, (int)this.posZ) || !this.worldObj.getChunkFromBlockCoords((int)this.posX, (int)this.posZ).isChunkLoaded))
1544            {
1545                if (this.posY > 0.0D)
1546                {
1547                    this.motionY = -0.1D;
1548                }
1549                else
1550                {
1551                    this.motionY = 0.0D;
1552                }
1553            }
1554            else
1555            {
1556                this.motionY -= 0.08D;
1557            }
1558
1559            this.motionY *= 0.9800000190734863D;
1560            this.motionX *= (double)var3;
1561            this.motionZ *= (double)var3;
1562        }
1563
1564        this.prevLegYaw = this.legYaw;
1565        var9 = this.posX - this.prevPosX;
1566        double var12 = this.posZ - this.prevPosZ;
1567        float var11 = MathHelper.sqrt_double(var9 * var9 + var12 * var12) * 4.0F;
1568
1569        if (var11 > 1.0F)
1570        {
1571            var11 = 1.0F;
1572        }
1573
1574        this.legYaw += (var11 - this.legYaw) * 0.4F;
1575        this.legSwing += this.legYaw;
1576    }
1577
1578    /**
1579     * returns true if this entity is by a ladder, false otherwise
1580     */
1581    public boolean isOnLadder()
1582    {
1583        int var1 = MathHelper.floor_double(this.posX);
1584        int var2 = MathHelper.floor_double(this.boundingBox.minY);
1585        int var3 = MathHelper.floor_double(this.posZ);
1586        int var4 = this.worldObj.getBlockId(var1, var2, var3);
1587        return ForgeHooks.isLivingOnLadder(Block.blocksList[var4], worldObj, var1, var2, var3);
1588    }
1589
1590    /**
1591     * (abstract) Protected helper method to write subclass entity data to NBT.
1592     */
1593    public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
1594    {
1595        if (this.health < -32768)
1596        {
1597            this.health = -32768;
1598        }
1599
1600        par1NBTTagCompound.setShort("Health", (short)this.health);
1601        par1NBTTagCompound.setShort("HurtTime", (short)this.hurtTime);
1602        par1NBTTagCompound.setShort("DeathTime", (short)this.deathTime);
1603        par1NBTTagCompound.setShort("AttackTime", (short)this.attackTime);
1604        par1NBTTagCompound.setBoolean("CanPickUpLoot", this.canPickUpLoot);
1605        par1NBTTagCompound.setBoolean("PersistenceRequired", this.persistenceRequired);
1606        NBTTagList var2 = new NBTTagList();
1607
1608        for (int var3 = 0; var3 < this.equipment.length; ++var3)
1609        {
1610            NBTTagCompound var4 = new NBTTagCompound();
1611
1612            if (this.equipment[var3] != null)
1613            {
1614                this.equipment[var3].writeToNBT(var4);
1615            }
1616
1617            var2.appendTag(var4);
1618        }
1619
1620        par1NBTTagCompound.setTag("Equipment", var2);
1621        NBTTagList var6;
1622
1623        if (!this.activePotionsMap.isEmpty())
1624        {
1625            var6 = new NBTTagList();
1626            Iterator var7 = this.activePotionsMap.values().iterator();
1627
1628            while (var7.hasNext())
1629            {
1630                PotionEffect var5 = (PotionEffect)var7.next();
1631                var6.appendTag(var5.writeCustomPotionEffectToNBT(new NBTTagCompound()));
1632            }
1633
1634            par1NBTTagCompound.setTag("ActiveEffects", var6);
1635        }
1636
1637        var6 = new NBTTagList();
1638
1639        for (int var8 = 0; var8 < this.equipmentDropChances.length; ++var8)
1640        {
1641            var6.appendTag(new NBTTagFloat(var8 + "", this.equipmentDropChances[var8]));
1642        }
1643
1644        par1NBTTagCompound.setTag("DropChances", var6);
1645    }
1646
1647    /**
1648     * (abstract) Protected helper method to read subclass entity data from NBT.
1649     */
1650    public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
1651    {
1652        this.health = par1NBTTagCompound.getShort("Health");
1653
1654        if (!par1NBTTagCompound.hasKey("Health"))
1655        {
1656            this.health = this.getMaxHealth();
1657        }
1658
1659        this.hurtTime = par1NBTTagCompound.getShort("HurtTime");
1660        this.deathTime = par1NBTTagCompound.getShort("DeathTime");
1661        this.attackTime = par1NBTTagCompound.getShort("AttackTime");
1662        this.canPickUpLoot = par1NBTTagCompound.getBoolean("CanPickUpLoot");
1663        this.persistenceRequired = par1NBTTagCompound.getBoolean("PersistenceRequired");
1664        NBTTagList var2;
1665        int var3;
1666
1667        if (par1NBTTagCompound.hasKey("Equipment"))
1668        {
1669            var2 = par1NBTTagCompound.getTagList("Equipment");
1670
1671            for (var3 = 0; var3 < this.equipment.length; ++var3)
1672            {
1673                this.equipment[var3] = ItemStack.loadItemStackFromNBT((NBTTagCompound)var2.tagAt(var3));
1674            }
1675        }
1676
1677        if (par1NBTTagCompound.hasKey("ActiveEffects"))
1678        {
1679            var2 = par1NBTTagCompound.getTagList("ActiveEffects");
1680
1681            for (var3 = 0; var3 < var2.tagCount(); ++var3)
1682            {
1683                NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
1684                PotionEffect var5 = PotionEffect.readCustomPotionEffectFromNBT(var4);
1685                this.activePotionsMap.put(Integer.valueOf(var5.getPotionID()), var5);
1686            }
1687        }
1688
1689        if (par1NBTTagCompound.hasKey("DropChances"))
1690        {
1691            var2 = par1NBTTagCompound.getTagList("DropChances");
1692
1693            for (var3 = 0; var3 < var2.tagCount(); ++var3)
1694            {
1695                this.equipmentDropChances[var3] = ((NBTTagFloat)var2.tagAt(var3)).data;
1696            }
1697        }
1698    }
1699
1700    /**
1701     * Checks whether target entity is alive.
1702     */
1703    public boolean isEntityAlive()
1704    {
1705        return !this.isDead && this.health > 0;
1706    }
1707
1708    public boolean canBreatheUnderwater()
1709    {
1710        return false;
1711    }
1712
1713    public void setMoveForward(float par1)
1714    {
1715        this.moveForward = par1;
1716    }
1717
1718    public void setJumping(boolean par1)
1719    {
1720        this.isJumping = par1;
1721    }
1722
1723    /**
1724     * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
1725     * use this to react to sunlight and start to burn.
1726     */
1727    public void onLivingUpdate()
1728    {
1729        if (this.jumpTicks > 0)
1730        {
1731            --this.jumpTicks;
1732        }
1733
1734        if (this.newPosRotationIncrements > 0)
1735        {
1736            double var1 = this.posX + (this.newPosX - this.posX) / (double)this.newPosRotationIncrements;
1737            double var3 = this.posY + (this.newPosY - this.posY) / (double)this.newPosRotationIncrements;
1738            double var5 = this.posZ + (this.newPosZ - this.posZ) / (double)this.newPosRotationIncrements;
1739            double var7 = MathHelper.wrapAngleTo180_double(this.newRotationYaw - (double)this.rotationYaw);
1740            this.rotationYaw = (float)((double)this.rotationYaw + var7 / (double)this.newPosRotationIncrements);
1741            this.rotationPitch = (float)((double)this.rotationPitch + (this.newRotationPitch - (double)this.rotationPitch) / (double)this.newPosRotationIncrements);
1742            --this.newPosRotationIncrements;
1743            this.setPosition(var1, var3, var5);
1744            this.setRotation(this.rotationYaw, this.rotationPitch);
1745        }
1746        else if (!this.isClientWorld())
1747        {
1748            this.motionX *= 0.98D;
1749            this.motionY *= 0.98D;
1750            this.motionZ *= 0.98D;
1751        }
1752
1753        if (Math.abs(this.motionX) < 0.005D)
1754        {
1755            this.motionX = 0.0D;
1756        }
1757
1758        if (Math.abs(this.motionY) < 0.005D)
1759        {
1760            this.motionY = 0.0D;
1761        }
1762
1763        if (Math.abs(this.motionZ) < 0.005D)
1764        {
1765            this.motionZ = 0.0D;
1766        }
1767
1768        this.worldObj.theProfiler.startSection("ai");
1769
1770        if (this.isMovementBlocked())
1771        {
1772            this.isJumping = false;
1773            this.moveStrafing = 0.0F;
1774            this.moveForward = 0.0F;
1775            this.randomYawVelocity = 0.0F;
1776        }
1777        else if (this.isClientWorld())
1778        {
1779            if (this.isAIEnabled())
1780            {
1781                this.worldObj.theProfiler.startSection("newAi");
1782                this.updateAITasks();
1783                this.worldObj.theProfiler.endSection();
1784            }
1785            else
1786            {
1787                this.worldObj.theProfiler.startSection("oldAi");
1788                this.updateEntityActionState();
1789                this.worldObj.theProfiler.endSection();
1790                this.rotationYawHead = this.rotationYaw;
1791            }
1792        }
1793
1794        this.worldObj.theProfiler.endSection();
1795        this.worldObj.theProfiler.startSection("jump");
1796
1797        if (this.isJumping)
1798        {
1799            if (!this.isInWater() && !this.handleLavaMovement())
1800            {
1801                if (this.onGround && this.jumpTicks == 0)
1802                {
1803                    this.jump();
1804                    this.jumpTicks = 10;
1805                }
1806            }
1807            else
1808            {
1809                this.motionY += 0.03999999910593033D;
1810            }
1811        }
1812        else
1813        {
1814            this.jumpTicks = 0;
1815        }
1816
1817        this.worldObj.theProfiler.endSection();
1818        this.worldObj.theProfiler.startSection("travel");
1819        this.moveStrafing *= 0.98F;
1820        this.moveForward *= 0.98F;
1821        this.randomYawVelocity *= 0.9F;
1822        float var11 = this.landMovementFactor;
1823        this.landMovementFactor *= this.getSpeedModifier();
1824        this.moveEntityWithHeading(this.moveStrafing, this.moveForward);
1825        this.landMovementFactor = var11;
1826        this.worldObj.theProfiler.endSection();
1827        this.worldObj.theProfiler.startSection("push");
1828
1829        if (!this.worldObj.isRemote)
1830        {
1831            this.func_85033_bc();
1832        }
1833
1834        this.worldObj.theProfiler.endSection();
1835        this.worldObj.theProfiler.startSection("looting");
1836
1837        if (!this.worldObj.isRemote && this.canPickUpLoot && !this.dead && this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"))
1838        {
1839            List var2 = this.worldObj.getEntitiesWithinAABB(EntityItem.class, this.boundingBox.expand(1.0D, 0.0D, 1.0D));
1840            Iterator var12 = var2.iterator();
1841
1842            while (var12.hasNext())
1843            {
1844                EntityItem var4 = (EntityItem)var12.next();
1845
1846                if (!var4.isDead && var4.getEntityItem() != null)
1847                {
1848                    ItemStack var13 = var4.getEntityItem();
1849                    int var6 = func_82159_b(var13);
1850
1851                    if (var6 > -1)
1852                    {
1853                        boolean var14 = true;
1854                        ItemStack var8 = this.getCurrentItemOrArmor(var6);
1855
1856                        if (var8 != null)
1857                        {
1858                            if (var6 == 0)
1859                            {
1860                                if (var13.getItem() instanceof ItemSword && !(var8.getItem() instanceof ItemSword))
1861                                {
1862                                    var14 = true;
1863                                }
1864                                else if (var13.getItem() instanceof ItemSword && var8.getItem() instanceof ItemSword)
1865                                {
1866                                    ItemSword var9 = (ItemSword)var13.getItem();
1867                                    ItemSword var10 = (ItemSword)var8.getItem();
1868
1869                                    if (var9.func_82803_g() == var10.func_82803_g())
1870                                    {
1871                                        var14 = var13.getItemDamage() > var8.getItemDamage() || var13.hasTagCompound() && !var8.hasTagCompound();
1872                                    }
1873                                    else
1874                                    {
1875                                        var14 = var9.func_82803_g() > var10.func_82803_g();
1876                                    }
1877                                }
1878                                else
1879                                {
1880                                    var14 = false;
1881                                }
1882                            }
1883                            else if (var13.getItem() instanceof ItemArmor && !(var8.getItem() instanceof ItemArmor))
1884                            {
1885                                var14 = true;
1886                            }
1887                            else if (var13.getItem() instanceof ItemArmor && var8.getItem() instanceof ItemArmor)
1888                            {
1889                                ItemArmor var15 = (ItemArmor)var13.getItem();
1890                                ItemArmor var16 = (ItemArmor)var8.getItem();
1891
1892                                if (var15.damageReduceAmount == var16.damageReduceAmount)
1893                                {
1894                                    var14 = var13.getItemDamage() > var8.getItemDamage() || var13.hasTagCompound() && !var8.hasTagCompound();
1895                                }
1896                                else
1897                                {
1898                                    var14 = var15.damageReduceAmount > var16.damageReduceAmount;
1899                                }
1900                            }
1901                            else
1902                            {
1903                                var14 = false;
1904                            }
1905                        }
1906
1907                        if (var14)
1908                        {
1909                            if (var8 != null && this.rand.nextFloat() - 0.1F < this.equipmentDropChances[var6])
1910                            {
1911                                this.entityDropItem(var8, 0.0F);
1912                            }
1913
1914                            this.setCurrentItemOrArmor(var6, var13);
1915                            this.equipmentDropChances[var6] = 2.0F;
1916                            this.persistenceRequired = true;
1917                            this.onItemPickup(var4, 1);
1918                            var4.setDead();
1919                        }
1920                    }
1921                }
1922            }
1923        }
1924
1925        this.worldObj.theProfiler.endSection();
1926    }
1927
1928    protected void func_85033_bc()
1929    {
1930        List var1 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D));
1931
1932        if (var1 != null && !var1.isEmpty())
1933        {
1934            for (int var2 = 0; var2 < var1.size(); ++var2)
1935            {
1936                Entity var3 = (Entity)var1.get(var2);
1937
1938                if (var3.canBePushed())
1939                {
1940                    this.collideWithEntity(var3);
1941                }
1942            }
1943        }
1944    }
1945
1946    protected void collideWithEntity(Entity par1Entity)
1947    {
1948        par1Entity.applyEntityCollision(this);
1949    }
1950
1951    /**
1952     * Returns true if the newer Entity AI code should be run
1953     */
1954    protected boolean isAIEnabled()
1955    {
1956        return false;
1957    }
1958
1959    /**
1960     * Returns whether the entity is in a local (client) world
1961     */
1962    protected boolean isClientWorld()
1963    {
1964        return !this.worldObj.isRemote;
1965    }
1966
1967    /**
1968     * Dead and sleeping entities cannot move
1969     */
1970    protected boolean isMovementBlocked()
1971    {
1972        return this.health <= 0;
1973    }
1974
1975    public boolean isBlocking()
1976    {
1977        return false;
1978    }
1979
1980    /**
1981     * Causes this entity to do an upwards motion (jumping).
1982     */
1983    protected void jump()
1984    {
1985        this.motionY = 0.41999998688697815D;
1986
1987        if (this.isPotionActive(Potion.jump))
1988        {
1989            this.motionY += (double)((float)(this.getActivePotionEffect(Potion.jump).getAmplifier() + 1) * 0.1F);
1990        }
1991
1992        if (this.isSprinting())
1993        {
1994            float var1 = this.rotationYaw * 0.017453292F;
1995            this.motionX -= (double)(MathHelper.sin(var1) * 0.2F);
1996            this.motionZ += (double)(MathHelper.cos(var1) * 0.2F);
1997        }
1998
1999        this.isAirBorne = true;
2000        ForgeHooks.onLivingJump(this);
2001    }
2002
2003    /**
2004     * Determines if an entity can be despawned, used on idle far away entities
2005     */
2006    protected boolean canDespawn()
2007    {
2008        return true;
2009    }
2010
2011    /**
2012     * Makes the entity despawn if requirements are reached
2013     */
2014    protected void despawnEntity()
2015    {
2016        if (!this.persistenceRequired)
2017        {
2018            EntityPlayer var1 = this.worldObj.getClosestPlayerToEntity(this, -1.0D);
2019
2020            if (var1 != null)
2021            {
2022                double var2 = var1.posX - this.posX;
2023                double var4 = var1.posY - this.posY;
2024                double var6 = var1.posZ - this.posZ;
2025                double var8 = var2 * var2 + var4 * var4 + var6 * var6;
2026
2027                if (this.canDespawn() && var8 > 16384.0D)
2028                {
2029                    this.setDead();
2030                }
2031
2032                if (this.entityAge > 600 && this.rand.nextInt(800) == 0 && var8 > 1024.0D && this.canDespawn())
2033                {
2034                    this.setDead();
2035                }
2036                else if (var8 < 1024.0D)
2037                {
2038                    this.entityAge = 0;
2039                }
2040            }
2041        }
2042    }
2043
2044    protected void updateAITasks()
2045    {
2046        ++this.entityAge;
2047        this.worldObj.theProfiler.startSection("checkDespawn");
2048        this.despawnEntity();
2049        this.worldObj.theProfiler.endSection();
2050        this.worldObj.theProfiler.startSection("sensing");
2051        this.senses.clearSensingCache();
2052        this.worldObj.theProfiler.endSection();
2053        this.worldObj.theProfiler.startSection("targetSelector");
2054        this.targetTasks.onUpdateTasks();
2055        this.worldObj.theProfiler.endSection();
2056        this.worldObj.theProfiler.startSection("goalSelector");
2057        this.tasks.onUpdateTasks();
2058        this.worldObj.theProfiler.endSection();
2059        this.worldObj.theProfiler.startSection("navigation");
2060        this.navigator.onUpdateNavigation();
2061        this.worldObj.theProfiler.endSection();
2062        this.worldObj.theProfiler.startSection("mob tick");
2063        this.updateAITick();
2064        this.worldObj.theProfiler.endSection();
2065        this.worldObj.theProfiler.startSection("controls");
2066        this.worldObj.theProfiler.startSection("move");
2067        this.moveHelper.onUpdateMoveHelper();
2068        this.worldObj.theProfiler.endStartSection("look");
2069        this.lookHelper.onUpdateLook();
2070        this.worldObj.theProfiler.endStartSection("jump");
2071        this.jumpHelper.doJump();
2072        this.worldObj.theProfiler.endSection();
2073        this.worldObj.theProfiler.endSection();
2074    }
2075
2076    /**
2077     * main AI tick function, replaces updateEntityActionState
2078     */
2079    protected void updateAITick() {}
2080
2081    protected void updateEntityActionState()
2082    {
2083        ++this.entityAge;
2084        this.despawnEntity();
2085        this.moveStrafing = 0.0F;
2086        this.moveForward = 0.0F;
2087        float var1 = 8.0F;
2088
2089        if (this.rand.nextFloat() < 0.02F)
2090        {
2091            EntityPlayer var2 = this.worldObj.getClosestPlayerToEntity(this, (double)var1);
2092
2093            if (var2 != null)
2094            {
2095                this.currentTarget = var2;
2096                this.numTicksToChaseTarget = 10 + this.rand.nextInt(20);
2097            }
2098            else
2099            {
2100                this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F;
2101            }
2102        }
2103
2104        if (this.currentTarget != null)
2105        {
2106            this.faceEntity(this.currentTarget, 10.0F, (float)this.getVerticalFaceSpeed());
2107
2108            if (this.numTicksToChaseTarget-- <= 0 || this.currentTarget.isDead || this.currentTarget.getDistanceSqToEntity(this) > (double)(var1 * var1))
2109            {
2110                this.currentTarget = null;
2111            }
2112        }
2113        else
2114        {
2115            if (this.rand.nextFloat() < 0.05F)
2116            {
2117                this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F;
2118            }
2119
2120            this.rotationYaw += this.randomYawVelocity;
2121            this.rotationPitch = this.defaultPitch;
2122        }
2123
2124        boolean var4 = this.isInWater();
2125        boolean var3 = this.handleLavaMovement();
2126
2127        if (var4 || var3)
2128        {
2129            this.isJumping = this.rand.nextFloat() < 0.8F;
2130        }
2131    }
2132
2133    /**
2134     * Updates the arm swing progress counters and animation progress
2135     */
2136    protected void updateArmSwingProgress()
2137    {
2138        int var1 = this.getArmSwingAnimationEnd();
2139
2140        if (this.isSwingInProgress)
2141        {
2142            ++this.swingProgressInt;
2143
2144            if (this.swingProgressInt >= var1)
2145            {
2146                this.swingProgressInt = 0;
2147                this.isSwingInProgress = false;
2148            }
2149        }
2150        else
2151        {
2152            this.swingProgressInt = 0;
2153        }
2154
2155        this.swingProgress = (float)this.swingProgressInt / (float)var1;
2156    }
2157
2158    /**
2159     * The speed it takes to move the entityliving's rotationPitch through the faceEntity method. This is only currently
2160     * use in wolves.
2161     */
2162    public int getVerticalFaceSpeed()
2163    {
2164        return 40;
2165    }
2166
2167    /**
2168     * Changes pitch and yaw so that the entity calling the function is facing the entity provided as an argument.
2169     */
2170    public void faceEntity(Entity par1Entity, float par2, float par3)
2171    {
2172        double var4 = par1Entity.posX - this.posX;
2173        double var8 = par1Entity.posZ - this.posZ;
2174        double var6;
2175
2176        if (par1Entity instanceof EntityLiving)
2177        {
2178            EntityLiving var10 = (EntityLiving)par1Entity;
2179            var6 = this.posY + (double)this.getEyeHeight() - (var10.posY + (double)var10.getEyeHeight());
2180        }
2181        else
2182        {
2183            var6 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) / 2.0D - (this.posY + (double)this.getEyeHeight());
2184        }
2185
2186        double var14 = (double)MathHelper.sqrt_double(var4 * var4 + var8 * var8);
2187        float var12 = (float)(Math.atan2(var8, var4) * 180.0D / Math.PI) - 90.0F;
2188        float var13 = (float)(-(Math.atan2(var6, var14) * 180.0D / Math.PI));
2189        this.rotationPitch = -this.updateRotation(this.rotationPitch, var13, par3);
2190        this.rotationYaw = this.updateRotation(this.rotationYaw, var12, par2);
2191    }
2192
2193    /**
2194     * Arguments: current rotation, intended rotation, max increment.
2195     */
2196    private float updateRotation(float par1, float par2, float par3)
2197    {
2198        float var4 = MathHelper.wrapAngleTo180_float(par2 - par1);
2199
2200        if (var4 > par3)
2201        {
2202            var4 = par3;
2203        }
2204
2205        if (var4 < -par3)
2206        {
2207            var4 = -par3;
2208        }
2209
2210        return par1 + var4;
2211    }
2212
2213    /**
2214     * Checks if the entity's current position is a valid location to spawn this entity.
2215     */
2216    public boolean getCanSpawnHere()
2217    {
2218        return this.worldObj.checkIfAABBIsClear(this.boundingBox) && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox);
2219    }
2220
2221    /**
2222     * sets the dead flag. Used when you fall off the bottom of the world.
2223     */
2224    protected void kill()
2225    {
2226        this.attackEntityFrom(DamageSource.outOfWorld, 4);
2227    }
2228
2229    @SideOnly(Side.CLIENT)
2230
2231    /**
2232     * Returns where in the swing animation the living entity is (from 0 to 1).  Args: partialTickTime
2233     */
2234    public float getSwingProgress(float par1)
2235    {
2236        float var2 = this.swingProgress - this.prevSwingProgress;
2237
2238        if (var2 < 0.0F)
2239        {
2240            ++var2;
2241        }
2242
2243        return this.prevSwingProgress + var2 * par1;
2244    }
2245
2246    @SideOnly(Side.CLIENT)
2247
2248    /**
2249     * interpolated position vector
2250     */
2251    public Vec3 getPosition(float par1)
2252    {
2253        if (par1 == 1.0F)
2254        {
2255            return this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
2256        }
2257        else
2258        {
2259            double var2 = this.prevPosX + (this.posX - this.prevPosX) * (double)par1;
2260            double var4 = this.prevPosY + (this.posY - this.prevPosY) * (double)par1;
2261            double var6 = this.prevPosZ + (this.posZ - this.prevPosZ) * (double)par1;
2262            return this.worldObj.getWorldVec3Pool().getVecFromPool(var2, var4, var6);
2263        }
2264    }
2265
2266    /**
2267     * returns a (normalized) vector of where this entity is looking
2268     */
2269    public Vec3 getLookVec()
2270    {
2271        return this.getLook(1.0F);
2272    }
2273
2274    /**
2275     * interpolated look vector
2276     */
2277    public Vec3 getLook(float par1)
2278    {
2279        float var2;
2280        float var3;
2281        float var4;
2282        float var5;
2283
2284        if (par1 == 1.0F)
2285        {
2286            var2 = MathHelper.cos(-this.rotationYaw * 0.017453292F - (float)Math.PI);
2287            var3 = MathHelper.sin(-this.rotationYaw * 0.017453292F - (float)Math.PI);
2288            var4 = -MathHelper.cos(-this.rotationPitch * 0.017453292F);
2289            var5 = MathHelper.sin(-this.rotationPitch * 0.017453292F);
2290            return this.worldObj.getWorldVec3Pool().getVecFromPool((double)(var3 * var4), (double)var5, (double)(var2 * var4));
2291        }
2292        else
2293        {
2294            var2 = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * par1;
2295            var3 = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * par1;
2296            var4 = MathHelper.cos(-var3 * 0.017453292F - (float)Math.PI);
2297            var5 = MathHelper.sin(-var3 * 0.017453292F - (float)Math.PI);
2298            float var6 = -MathHelper.cos(-var2 * 0.017453292F);
2299            float var7 = MathHelper.sin(-var2 * 0.017453292F);
2300            return this.worldObj.getWorldVec3Pool().getVecFromPool((double)(var5 * var6), (double)var7, (double)(var4 * var6));
2301        }
2302    }
2303
2304    @SideOnly(Side.CLIENT)
2305
2306    /**
2307     * Returns render size modifier
2308     */
2309    public float getRenderSizeModifier()
2310    {
2311        return 1.0F;
2312    }
2313
2314    @SideOnly(Side.CLIENT)
2315
2316    /**
2317     * Performs a ray trace for the distance specified and using the partial tick time. Args: distance, partialTickTime
2318     */
2319    public MovingObjectPosition rayTrace(double par1, float par3)
2320    {
2321        Vec3 var4 = this.getPosition(par3);
2322        Vec3 var5 = this.getLook(par3);
2323        Vec3 var6 = var4.addVector(var5.xCoord * par1, var5.yCoord * par1, var5.zCoord * par1);
2324        return this.worldObj.rayTraceBlocks(var4, var6);
2325    }
2326
2327    /**
2328     * Will return how many at most can spawn in a chunk at once.
2329     */
2330    public int getMaxSpawnedInChunk()
2331    {
2332        return 4;
2333    }
2334
2335    @SideOnly(Side.CLIENT)
2336    public void handleHealthUpdate(byte par1)
2337    {
2338        if (par1 == 2)
2339        {
2340            this.legYaw = 1.5F;
2341            this.hurtResistantTime = this.maxHurtResistantTime;
2342            this.hurtTime = this.maxHurtTime = 10;
2343            this.attackedAtYaw = 0.0F;
2344            this.playSound(this.getHurtSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
2345            this.attackEntityFrom(DamageSource.generic, 0);
2346        }
2347        else if (par1 == 3)
2348        {
2349            this.playSound(this.getDeathSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
2350            this.health = 0;
2351            this.onDeath(DamageSource.generic);
2352        }
2353        else
2354        {
2355            super.handleHealthUpdate(par1);
2356        }
2357    }
2358
2359    /**
2360     * Returns whether player is sleeping or not
2361     */
2362    public boolean isPlayerSleeping()
2363    {
2364        return false;
2365    }
2366
2367    @SideOnly(Side.CLIENT)
2368
2369    /**
2370     * Gets the Icon Index of the item currently held
2371     */
2372    public int getItemIcon(ItemStack par1ItemStack, int par2)
2373    {
2374        return par1ItemStack.getIconIndex();
2375    }
2376
2377    protected void updatePotionEffects()
2378    {
2379        Iterator var1 = this.activePotionsMap.keySet().iterator();
2380
2381        while (var1.hasNext())
2382        {
2383            Integer var2 = (Integer)var1.next();
2384            PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2);
2385
2386            if (!var3.onUpdate(this))
2387            {
2388                if (!this.worldObj.isRemote)
2389                {
2390                    var1.remove();
2391                    this.onFinishedPotionEffect(var3);
2392                }
2393            }
2394            else if (var3.getDuration() % 600 == 0)
2395            {
2396                this.onChangedPotionEffect(var3);
2397            }
2398        }
2399
2400        int var11;
2401
2402        if (this.potionsNeedUpdate)
2403        {
2404            if (!this.worldObj.isRemote)
2405            {
2406                if (this.activePotionsMap.isEmpty())
2407                {
2408                    this.dataWatcher.updateObject(9, Byte.valueOf((byte)0));
2409                    this.dataWatcher.updateObject(8, Integer.valueOf(0));
2410                    this.setHasActivePotion(false);
2411                }
2412                else
2413                {
2414                    var11 = PotionHelper.calcPotionLiquidColor(this.activePotionsMap.values());
2415                    this.dataWatcher.updateObject(9, Byte.valueOf((byte)(PotionHelper.func_82817_b(this.activePotionsMap.values()) ? 1 : 0)));
2416                    this.dataWatcher.updateObject(8, Integer.valueOf(var11));
2417                    this.setHasActivePotion(this.isPotionActive(Potion.invisibility.id));
2418                }
2419            }
2420
2421            this.potionsNeedUpdate = false;
2422        }
2423
2424        var11 = this.dataWatcher.getWatchableObjectInt(8);
2425        boolean var12 = this.dataWatcher.getWatchableObjectByte(9) > 0;
2426
2427        if (var11 > 0)
2428        {
2429            boolean var4 = false;
2430
2431            if (!this.getHasActivePotion())
2432            {
2433                var4 = this.rand.nextBoolean();
2434            }
2435            else
2436            {
2437                var4 = this.rand.nextInt(15) == 0;
2438            }
2439
2440            if (var12)
2441            {
2442                var4 &= this.rand.nextInt(5) == 0;
2443            }
2444
2445            if (var4 && var11 > 0)
2446            {
2447                double var5 = (double)(var11 >> 16 & 255) / 255.0D;
2448                double var7 = (double)(var11 >> 8 & 255) / 255.0D;
2449                double var9 = (double)(var11 >> 0 & 255) / 255.0D;
2450                this.worldObj.spawnParticle(var12 ? "mobSpellAmbient" : "mobSpell", this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height - (double)this.yOffset, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, var5, var7, var9);
2451            }
2452        }
2453    }
2454
2455    public void clearActivePotions()
2456    {
2457        Iterator var1 = this.activePotionsMap.keySet().iterator();
2458
2459        while (var1.hasNext())
2460        {
2461            Integer var2 = (Integer)var1.next();
2462            PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2);
2463
2464            if (!this.worldObj.isRemote)
2465            {
2466                var1.remove();
2467                this.onFinishedPotionEffect(var3);
2468            }
2469        }
2470    }
2471
2472    public Collection getActivePotionEffects()
2473    {
2474        return this.activePotionsMap.values();
2475    }
2476
2477    public boolean isPotionActive(int par1)
2478    {
2479        return this.activePotionsMap.containsKey(Integer.valueOf(par1));
2480    }
2481
2482    public boolean isPotionActive(Potion par1Potion)
2483    {
2484        return this.activePotionsMap.containsKey(Integer.valueOf(par1Potion.id));
2485    }
2486
2487    /**
2488     * returns the PotionEffect for the supplied Potion if it is active, null otherwise.
2489     */
2490    public PotionEffect getActivePotionEffect(Potion par1Potion)
2491    {
2492        return (PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1Potion.id));
2493    }
2494
2495    /**
2496     * adds a PotionEffect to the entity
2497     */
2498    public void addPotionEffect(PotionEffect par1PotionEffect)
2499    {
2500        if (this.isPotionApplicable(par1PotionEffect))
2501        {
2502            if (this.activePotionsMap.containsKey(Integer.valueOf(par1PotionEffect.getPotionID())))
2503            {
2504                ((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID()))).combine(par1PotionEffect);
2505                this.onChangedPotionEffect((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID())));
2506            }
2507            else
2508            {
2509                this.activePotionsMap.put(Integer.valueOf(par1PotionEffect.getPotionID()), par1PotionEffect);
2510                this.onNewPotionEffect(par1PotionEffect);
2511            }
2512        }
2513    }
2514
2515    public boolean isPotionApplicable(PotionEffect par1PotionEffect)
2516    {
2517        if (this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD)
2518        {
2519            int var2 = par1PotionEffect.getPotionID();
2520
2521            if (var2 == Potion.regeneration.id || var2 == Potion.poison.id)
2522            {
2523                return false;
2524            }
2525        }
2526
2527        return true;
2528    }
2529
2530    /**
2531     * Returns true if this entity is undead.
2532     */
2533    public boolean isEntityUndead()
2534    {
2535        return this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD;
2536    }
2537
2538    /**
2539     * Remove the speified potion effect from this entity.
2540     */
2541    public void removePotionEffectClient(int par1)
2542    {
2543        this.activePotionsMap.remove(Integer.valueOf(par1));
2544    }
2545
2546    /**
2547     * Remove the specified potion effect from this entity.
2548     */
2549    public void removePotionEffect(int par1)
2550    {
2551        PotionEffect var2 = (PotionEffect)this.activePotionsMap.remove(Integer.valueOf(par1));
2552
2553        if (var2 != null)
2554        {
2555            this.onFinishedPotionEffect(var2);
2556        }
2557    }
2558
2559    protected void onNewPotionEffect(PotionEffect par1PotionEffect)
2560    {
2561        this.potionsNeedUpdate = true;
2562    }
2563
2564    protected void onChangedPotionEffect(PotionEffect par1PotionEffect)
2565    {
2566        this.potionsNeedUpdate = true;
2567    }
2568
2569    protected void onFinishedPotionEffect(PotionEffect par1PotionEffect)
2570    {
2571        this.potionsNeedUpdate = true;
2572    }
2573
2574    /**
2575     * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown
2576     * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities.
2577     */
2578    public float getSpeedModifier()
2579    {
2580        float var1 = 1.0F;
2581
2582        if (this.isPotionActive(Potion.moveSpeed))
2583        {
2584            var1 *= 1.0F + 0.2F * (float)(this.getActivePotionEffect(Potion.moveSpeed).getAmplifier() + 1);
2585        }
2586
2587        if (this.isPotionActive(Potion.moveSlowdown))
2588        {
2589            var1 *= 1.0F - 0.15F * (float)(this.getActivePotionEffect(Potion.moveSlowdown).getAmplifier() + 1);
2590        }
2591
2592        return var1;
2593    }
2594
2595    /**
2596     * Move the entity to the coordinates informed, but keep yaw/pitch values.
2597     */
2598    public void setPositionAndUpdate(double par1, double par3, double par5)
2599    {
2600        this.setLocationAndAngles(par1, par3, par5, this.rotationYaw, this.rotationPitch);
2601    }
2602
2603    /**
2604     * If Animal, checks if the age timer is negative
2605     */
2606    public boolean isChild()
2607    {
2608        return false;
2609    }
2610
2611    /**
2612     * Get this Entity's EnumCreatureAttribute
2613     */
2614    public EnumCreatureAttribute getCreatureAttribute()
2615    {
2616        return EnumCreatureAttribute.UNDEFINED;
2617    }
2618
2619    /**
2620     * Renders broken item particles using the given ItemStack
2621     */
2622    public void renderBrokenItemStack(ItemStack par1ItemStack)
2623    {
2624        this.playSound("random.break", 0.8F, 0.8F + this.worldObj.rand.nextFloat() * 0.4F);
2625
2626        for (int var2 = 0; var2 < 5; ++var2)
2627        {
2628            Vec3 var3 = this.worldObj.getWorldVec3Pool().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D);
2629            var3.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F);
2630            var3.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F);
2631            Vec3 var4 = this.worldObj.getWorldVec3Pool().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.3D, (double)(-this.rand.nextFloat()) * 0.6D - 0.3D, 0.6D);
2632            var4.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F);
2633            var4.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F);
2634            var4 = var4.addVector(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ);
2635            this.worldObj.spawnParticle("iconcrack_" + par1ItemStack.getItem().itemID, var4.xCoord, var4.yCoord, var4.zCoord, var3.xCoord, var3.yCoord + 0.05D, var3.zCoord);
2636        }
2637    }
2638
2639    public int func_82143_as()
2640    {
2641        if (this.getAttackTarget() == null)
2642        {
2643            return 3;
2644        }
2645        else
2646        {
2647            int var1 = (int)((float)this.health - (float)this.getMaxHealth() * 0.33F);
2648            var1 -= (3 - this.worldObj.difficultySetting) * 4;
2649
2650            if (var1 < 0)
2651            {
2652                var1 = 0;
2653            }
2654
2655            return var1 + 3;
2656        }
2657    }
2658
2659    /**
2660     * Returns the item that this EntityLiving is holding, if any.
2661     */
2662    public ItemStack getHeldItem()
2663    {
2664        return this.equipment[0];
2665    }
2666
2667    /**
2668     * 0 = item, 1-n is armor
2669     */
2670    public ItemStack getCurrentItemOrArmor(int par1)
2671    {
2672        return this.equipment[par1];
2673    }
2674
2675    public ItemStack getCurrentArmor(int par1)
2676    {
2677        return this.equipment[par1 + 1];
2678    }
2679
2680    /**
2681     * Sets the held item, or an armor slot. Slot 0 is held item. Slot 1-4 is armor. Params: Item, slot
2682     */
2683    public void setCurrentItemOrArmor(int par1, ItemStack par2ItemStack)
2684    {
2685        this.equipment[par1] = par2ItemStack;
2686    }
2687
2688    public ItemStack[] getLastActiveItems()
2689    {
2690        return this.equipment;
2691    }
2692
2693    /**
2694     * Drop the equipment for this entity.
2695     */
2696    protected void dropEquipment(boolean par1, int par2)
2697    {
2698        for (int var3 = 0; var3 < this.getLastActiveItems().length; ++var3)
2699        {
2700            ItemStack var4 = this.getCurrentItemOrArmor(var3);
2701            boolean var5 = this.equipmentDropChances[var3] > 1.0F;
2702
2703            if (var4 != null && (par1 || var5) && this.rand.nextFloat() - (float)par2 * 0.01F < this.equipmentDropChances[var3])
2704            {
2705                if (!var5 && var4.isItemStackDamageable())
2706                {
2707                    int var6 = Math.max(var4.getMaxDamage() - 25, 1);
2708                    int var7 = var4.getMaxDamage() - this.rand.nextInt(this.rand.nextInt(var6) + 1);
2709
2710                    if (var7 > var6)
2711                    {
2712                        var7 = var6;
2713                    }
2714
2715                    if (var7 < 1)
2716                    {
2717                        var7 = 1;
2718                    }
2719
2720                    var4.setItemDamage(var7);
2721                }
2722
2723                this.entityDropItem(var4, 0.0F);
2724            }
2725        }
2726    }
2727
2728    protected void func_82164_bB()
2729    {
2730        if (this.rand.nextFloat() < armorProbability[this.worldObj.difficultySetting])
2731        {
2732            int var1 = this.rand.nextInt(2);
2733            float var2 = this.worldObj.difficultySetting == 3 ? 0.1F : 0.25F;
2734
2735            if (this.rand.nextFloat() < 0.1F)
2736            {
2737                ++var1;
2738            }
2739
2740            if (this.rand.nextFloat() < 0.1F)
2741            {
2742                ++var1;
2743            }
2744
2745            if (this.rand.nextFloat() < 0.1F)
2746            {
2747                ++var1;
2748            }
2749
2750            for (int var3 = 3; var3 >= 0; --var3)
2751            {
2752                ItemStack var4 = this.getCurrentArmor(var3);
2753
2754                if (var3 < 3 && this.rand.nextFloat() < var2)
2755                {
2756                    break;
2757                }
2758
2759                if (var4 == null)
2760                {
2761                    Item var5 = getArmorItemForSlot(var3 + 1, var1);
2762
2763                    if (var5 != null)
2764                    {
2765                        this.setCurrentItemOrArmor(var3 + 1, new ItemStack(var5));
2766                    }
2767                }
2768            }
2769        }
2770    }
2771
2772    /**
2773     * Called whenever an item is picked up from walking over it. Args: pickedUpEntity, stackSize
2774     */
2775    public void onItemPickup(Entity par1Entity, int par2)
2776    {
2777        if (!par1Entity.isDead && !this.worldObj.isRemote)
2778        {
2779            EntityTracker var3 = ((WorldServer)this.worldObj).getEntityTracker();
2780
2781            if (par1Entity instanceof EntityItem)
2782            {
2783                var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId));
2784            }
2785
2786            if (par1Entity instanceof EntityArrow)
2787            {
2788                var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId));
2789            }
2790
2791            if (par1Entity instanceof EntityXPOrb)
2792            {
2793                var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId));
2794            }
2795        }
2796    }
2797
2798    public static int func_82159_b(ItemStack par0ItemStack)
2799    {
2800        if (par0ItemStack.itemID != Block.pumpkin.blockID && par0ItemStack.itemID != Item.skull.itemID)
2801        {
2802            if (par0ItemStack.getItem() instanceof ItemArmor)
2803            {
2804                switch (((ItemArmor)par0ItemStack.getItem()).armorType)
2805                {
2806                    case 0:
2807                        return 4;
2808                    case 1:
2809                        return 3;
2810                    case 2:
2811                        return 2;
2812                    case 3:
2813                        return 1;
2814                }
2815            }
2816
2817            return 0;
2818        }
2819        else
2820        {
2821            return 4;
2822        }
2823    }
2824
2825    /**
2826     * Params: Armor slot, Item tier
2827     */
2828    public static Item getArmorItemForSlot(int par0, int par1)
2829    {
2830        switch (par0)
2831        {
2832            case 4:
2833                if (par1 == 0)
2834                {
2835                    return Item.helmetLeather;
2836                }
2837                else if (par1 == 1)
2838                {
2839                    return Item.helmetGold;
2840                }
2841                else if (par1 == 2)
2842                {
2843                    return Item.helmetChain;
2844                }
2845                else if (par1 == 3)
2846                {
2847                    return Item.helmetSteel;
2848                }
2849                else if (par1 == 4)
2850                {
2851                    return Item.helmetDiamond;
2852                }
2853            case 3:
2854                if (par1 == 0)
2855                {
2856                    return Item.plateLeather;
2857                }
2858                else if (par1 == 1)
2859                {
2860                    return Item.plateGold;
2861                }
2862                else if (par1 == 2)
2863                {
2864                    return Item.plateChain;
2865                }
2866                else if (par1 == 3)
2867                {
2868                    return Item.plateSteel;
2869                }
2870                else if (par1 == 4)
2871                {
2872                    return Item.plateDiamond;
2873                }
2874            case 2:
2875                if (par1 == 0)
2876                {
2877                    return Item.legsLeather;
2878                }
2879                else if (par1 == 1)
2880                {
2881                    return Item.legsGold;
2882                }
2883                else if (par1 == 2)
2884                {
2885                    return Item.legsChain;
2886                }
2887                else if (par1 == 3)
2888                {
2889                    return Item.legsSteel;
2890                }
2891                else if (par1 == 4)
2892                {
2893                    return Item.legsDiamond;
2894                }
2895            case 1:
2896                if (par1 == 0)
2897                {
2898                    return Item.bootsLeather;
2899                }
2900                else if (par1 == 1)
2901                {
2902                    return Item.bootsGold;
2903                }
2904                else if (par1 == 2)
2905                {
2906                    return Item.bootsChain;
2907                }
2908                else if (par1 == 3)
2909                {
2910                    return Item.bootsSteel;
2911                }
2912                else if (par1 == 4)
2913                {
2914                    return Item.bootsDiamond;
2915                }
2916            default:
2917                return null;
2918        }
2919    }
2920
2921    protected void func_82162_bC()
2922    {
2923        if (this.getHeldItem() != null && this.rand.nextFloat() < enchantmentProbability[this.worldObj.difficultySetting])
2924        {
2925            EnchantmentHelper.addRandomEnchantment(this.rand, this.getHeldItem(), 5 + this.worldObj.difficultySetting * this.rand.nextInt(6));
2926        }
2927
2928        for (int var1 = 0; var1 < 4; ++var1)
2929        {
2930            ItemStack var2 = this.getCurrentArmor(var1);
2931
2932            if (var2 != null && this.rand.nextFloat() < armorEnchantmentProbability[this.worldObj.difficultySetting])
2933            {
2934                EnchantmentHelper.addRandomEnchantment(this.rand, var2, 5 + this.worldObj.difficultySetting * this.rand.nextInt(6));
2935            }
2936        }
2937    }
2938
2939    /**
2940     * Initialize this creature.
2941     */
2942    public void initCreature() {}
2943
2944    /**
2945     * Returns an integer indicating the end point of the swing animation, used by {@link #swingProgress} to provide a
2946     * progress indicator. Takes dig speed enchantments into account.
2947     */
2948    private int getArmSwingAnimationEnd()
2949    {
2950        return this.isPotionActive(Potion.digSpeed) ? 6 - (1 + this.getActivePotionEffect(Potion.digSpeed).getAmplifier()) * 1 : (this.isPotionActive(Potion.digSlowdown) ? 6 + (1 + this.getActivePotionEffect(Potion.digSlowdown).getAmplifier()) * 2 : 6);
2951    }
2952
2953    /**
2954     * Swings the item the player is holding.
2955     */
2956    public void swingItem()
2957    {
2958        if (!this.isSwingInProgress || this.swingProgressInt >= this.getArmSwingAnimationEnd() / 2 || this.swingProgressInt < 0)
2959        {
2960            this.swingProgressInt = -1;
2961            this.isSwingInProgress = true;
2962
2963            if (this.worldObj instanceof WorldServer)
2964            {
2965                ((WorldServer)this.worldObj).getEntityTracker().sendPacketToAllPlayersTrackingEntity(this, new Packet18Animation(this, 1));
2966            }
2967        }
2968    }
2969
2970    /**
2971     * returns true if all the conditions for steering the entity are met. For pigs, this is true if it is being ridden
2972     * by a player and the player is holding a carrot-on-a-stick
2973     */
2974    public boolean canBeSteered()
2975    {
2976        return false;
2977    }
2978
2979    /**
2980     * counts the amount of arrows stuck in the entity. getting hit by arrows increases this, used in rendering
2981     */
2982    public final int getArrowCountInEntity()
2983    {
2984        return this.dataWatcher.getWatchableObjectByte(10);
2985    }
2986
2987    /**
2988     * sets the amount of arrows stuck in the entity. used for rendering those
2989     */
2990    public final void setArrowCountInEntity(int par1)
2991    {
2992        this.dataWatcher.updateObject(10, Byte.valueOf((byte)par1));
2993    }
2994
2995    /***
2996     * Removes all potion effects that have curativeItem as a curative item for its effect
2997     * @param curativeItem The itemstack we are using to cure potion effects
2998     */
2999    public void curePotionEffects(ItemStack curativeItem)
3000    {
3001        Iterator<Integer> potionKey = activePotionsMap.keySet().iterator();
3002
3003        if (worldObj.isRemote)
3004        {
3005            return;
3006        }
3007
3008        while (potionKey.hasNext())
3009        {
3010            Integer key = potionKey.next();
3011            PotionEffect effect = (PotionEffect)activePotionsMap.get(key);
3012
3013            if (effect.isCurativeItem(curativeItem))
3014            {
3015                potionKey.remove();
3016                onFinishedPotionEffect(effect);
3017            }
3018        }
3019    }
3020
3021    /**
3022     * Returns true if the entity's rider (EntityPlayer) should face forward when mounted.
3023     * currently only used in vanilla code by pigs.
3024     *
3025     * @param player The player who is riding the entity.
3026     * @return If the player should orient the same direction as this entity.
3027     */
3028    public boolean shouldRiderFaceForward(EntityPlayer player)
3029    {
3030        return this instanceof EntityPig;
3031    }
3032}