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