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