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        public int maxHurtResistantTime = 20;
018        public float field_70769_ao;
019        public float field_70770_ap;
020        public float renderYawOffset = 0.0F;
021        public float prevRenderYawOffset = 0.0F;
022    
023        /** Entity head rotation yaw */
024        public float rotationYawHead = 0.0F;
025    
026        /** Entity head rotation yaw at previous tick */
027        public float prevRotationYawHead = 0.0F;
028        protected float field_70768_au;
029        protected float field_70766_av;
030        protected float field_70764_aw;
031        protected float field_70763_ax;
032        protected boolean field_70753_ay = true;
033    
034        /** the path for the texture of this entityLiving */
035        protected String texture = "/mob/char.png";
036        protected boolean field_70740_aA = true;
037        protected float field_70741_aB = 0.0F;
038    
039        /**
040         * a string holding the type of entity it is currently only implemented in entityPlayer(as 'humanoid')
041         */
042        protected String entityType = null;
043        protected float field_70743_aD = 1.0F;
044    
045        /** The score value of the Mob, the amount of points the mob is worth. */
046        protected int scoreValue = 0;
047        protected float field_70745_aF = 0.0F;
048    
049        /**
050         * A factor used to determine how far this entity will move each tick if it is walking on land. Adjusted by speed,
051         * and slipperiness of the current block.
052         */
053        public float landMovementFactor = 0.1F;
054    
055        /**
056         * A factor used to determine how far this entity will move each tick if it is jumping or falling.
057         */
058        public float jumpMovementFactor = 0.02F;
059        public float prevSwingProgress;
060        public float swingProgress;
061        protected int health = this.getMaxHealth();
062        public int prevHealth;
063    
064        /**
065         * in each step in the damage calculations, this is set to the 'carryover' that would result if someone was damaged
066         * .25 hearts (for example), and added to the damage in the next step
067         */
068        public int carryoverDamage;
069    
070        /** Number of ticks since this EntityLiving last produced its sound */
071        private int livingSoundTime;
072    
073        /**
074         * The amount of time remaining this entity should act 'hurt'. (Visual appearance of red tint)
075         */
076        public int hurtTime;
077    
078        /** What the hurt time was max set to last. */
079        public int maxHurtTime;
080    
081        /** The yaw at which this entity was last attacked from. */
082        public float attackedAtYaw = 0.0F;
083    
084        /**
085         * The amount of time remaining this entity should act 'dead', i.e. have a corpse in the world.
086         */
087        public int deathTime = 0;
088        public int attackTime = 0;
089        public float prevCameraPitch;
090        public float cameraPitch;
091    
092        /**
093         * This gets set on entity death, but never used. Looks like a duplicate of isDead
094         */
095        protected boolean dead = false;
096    
097        /** The experience points the Entity gives. */
098        protected int experienceValue;
099        public int field_70731_aW = -1;
100        public float field_70730_aX = (float)(Math.random() * 0.8999999761581421D + 0.10000000149011612D);
101        public float prevLegYaw;
102        public float legYaw;
103        public float field_70754_ba;
104    
105        /** The most recent player that has attacked this entity */
106        protected EntityPlayer attackingPlayer = null;
107    
108        /**
109         * Set to 60 when hit by the player or the player's wolf, then decrements. Used to determine whether the entity
110         * should drop items on death.
111         */
112        protected int recentlyHit = 0;
113    
114        /** is only being set, has no uses as of MC 1.1 */
115        private EntityLiving entityLivingToAttack = null;
116        private int revengeTimer = 0;
117        private EntityLiving lastAttackingEntity = null;
118    
119        /**
120         * Set to 60 when hit by the player or the player's wolf, then decrements. Used to determine whether the entity
121         * should drop items on death.
122         */
123        public int arrowHitTempCounter = 0;
124        public int arrowHitTimer = 0;
125        protected HashMap activePotionsMap = new HashMap();
126    
127        /** Whether the DataWatcher needs to be updated with the active potions */
128        private boolean potionsNeedUpdate = true;
129        private int field_70748_f;
130        private EntityLookHelper lookHelper;
131        private EntityMoveHelper moveHelper;
132    
133        /** Entity jumping helper */
134        private EntityJumpHelper jumpHelper;
135        private EntityBodyHelper bodyHelper;
136        private PathNavigate navigator;
137        public final EntityAITasks tasks;
138        protected final EntityAITasks targetTasks;
139    
140        /** The active target the Task system uses for tracking */
141        private EntityLiving attackTarget;
142        private EntitySenses senses;
143        private float AIMoveSpeed;
144        private ChunkCoordinates homePosition = new ChunkCoordinates(0, 0, 0);
145    
146        /** If -1 there is no maximum distance */
147        private float maximumHomeDistance = -1.0F;
148    
149        /**
150         * The number of updates over which the new position and rotation are to be applied to the entity.
151         */
152        protected int newPosRotationIncrements;
153    
154        /** The new X position to be applied to the entity. */
155        protected double newPosX;
156    
157        /** The new Y position to be applied to the entity. */
158        protected double newPosY;
159    
160        /** The new Z position to be applied to the entity. */
161        protected double newPosZ;
162    
163        /** The new yaw rotation to be applied to the entity. */
164        protected double newRotationYaw;
165    
166        /** The new yaw rotation to be applied to the entity. */
167        protected double newRotationPitch;
168        float field_70706_bo = 0.0F;
169    
170        /** Amount of damage taken in last hit, in half-hearts */
171        protected int lastDamage = 0;
172    
173        /** Holds the living entity age, used to control the despawn. */
174        protected int entityAge = 0;
175        protected float moveStrafing;
176        protected float moveForward;
177        protected float randomYawVelocity;
178    
179        /** used to check whether entity is jumping. */
180        public boolean isJumping = false;
181        protected float defaultPitch = 0.0F;
182        protected float moveSpeed = 0.7F;
183    
184        /** Number of ticks since last jump */
185        private int jumpTicks = 0;
186    
187        /** This entity's current target. */
188        private Entity currentTarget;
189    
190        /** How long to keep a specific target entity */
191        protected int numTicksToChaseTarget = 0;
192    
193        public EntityLiving(World par1World)
194        {
195            super(par1World);
196            this.preventEntitySpawning = true;
197            this.tasks = new EntityAITasks(par1World != null && par1World.theProfiler != null ? par1World.theProfiler : null);
198            this.targetTasks = new EntityAITasks(par1World != null && par1World.theProfiler != null ? par1World.theProfiler : null);
199            this.lookHelper = new EntityLookHelper(this);
200            this.moveHelper = new EntityMoveHelper(this);
201            this.jumpHelper = new EntityJumpHelper(this);
202            this.bodyHelper = new EntityBodyHelper(this);
203            this.navigator = new PathNavigate(this, par1World, 16.0F);
204            this.senses = new EntitySenses(this);
205            this.field_70770_ap = (float)(Math.random() + 1.0D) * 0.01F;
206            this.setPosition(this.posX, this.posY, this.posZ);
207            this.field_70769_ao = (float)Math.random() * 12398.0F;
208            this.rotationYaw = (float)(Math.random() * Math.PI * 2.0D);
209            this.rotationYawHead = this.rotationYaw;
210            this.stepHeight = 0.5F;
211        }
212    
213        public EntityLookHelper getLookHelper()
214        {
215            return this.lookHelper;
216        }
217    
218        public EntityMoveHelper getMoveHelper()
219        {
220            return this.moveHelper;
221        }
222    
223        public EntityJumpHelper getJumpHelper()
224        {
225            return this.jumpHelper;
226        }
227    
228        public PathNavigate getNavigator()
229        {
230            return this.navigator;
231        }
232    
233        /**
234         * returns the EntitySenses Object for the EntityLiving
235         */
236        public EntitySenses getEntitySenses()
237        {
238            return this.senses;
239        }
240    
241        public Random getRNG()
242        {
243            return this.rand;
244        }
245    
246        public EntityLiving getAITarget()
247        {
248            return this.entityLivingToAttack;
249        }
250    
251        public EntityLiving getLastAttackingEntity()
252        {
253            return this.lastAttackingEntity;
254        }
255    
256        public void setLastAttackingEntity(Entity par1Entity)
257        {
258            if (par1Entity instanceof EntityLiving)
259            {
260                this.lastAttackingEntity = (EntityLiving)par1Entity;
261            }
262        }
263    
264        public int getAge()
265        {
266            return this.entityAge;
267        }
268    
269        public float func_70079_am()
270        {
271            return this.rotationYawHead;
272        }
273    
274        @SideOnly(Side.CLIENT)
275    
276        /**
277         * Sets the head's yaw rotation of the entity.
278         */
279        public void setHeadRotationYaw(float par1)
280        {
281            this.rotationYawHead = par1;
282        }
283    
284        /**
285         * the movespeed used for the new AI system
286         */
287        public float getAIMoveSpeed()
288        {
289            return this.AIMoveSpeed;
290        }
291    
292        /**
293         * set the movespeed used for the new AI system
294         */
295        public void setAIMoveSpeed(float par1)
296        {
297            this.AIMoveSpeed = par1;
298            this.setMoveForward(par1);
299        }
300    
301        public boolean attackEntityAsMob(Entity par1Entity)
302        {
303            this.setLastAttackingEntity(par1Entity);
304            return false;
305        }
306    
307        /**
308         * Gets the active target the Task system uses for tracking
309         */
310        public EntityLiving getAttackTarget()
311        {
312            return this.attackTarget;
313        }
314    
315        /**
316         * Sets the active target the Task system uses for tracking
317         */
318        public void setAttackTarget(EntityLiving par1EntityLiving)
319        {
320            this.attackTarget = par1EntityLiving;
321            ForgeHooks.onLivingSetAttackTarget(this, par1EntityLiving);
322        }
323    
324        public boolean isExplosiveMob(Class par1Class)
325        {
326            return EntityCreeper.class != par1Class && EntityGhast.class != par1Class;
327        }
328    
329        /**
330         * This function applies the benefits of growing back wool and faster growing up to the acting entity. (This
331         * function is used in the AIEatGrass)
332         */
333        public void eatGrassBonus() {}
334    
335        /**
336         * Returns true if entity is within home distance from current position
337         */
338        public boolean isWithinHomeDistanceCurrentPosition()
339        {
340            return this.isWithinHomeDistance(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ));
341        }
342    
343        public boolean isWithinHomeDistance(int par1, int par2, int par3)
344        {
345            return this.maximumHomeDistance == -1.0F ? true : this.homePosition.getDistanceSquared(par1, par2, par3) < this.maximumHomeDistance * this.maximumHomeDistance;
346        }
347    
348        public void setHomeArea(int par1, int par2, int par3, int par4)
349        {
350            this.homePosition.set(par1, par2, par3);
351            this.maximumHomeDistance = (float)par4;
352        }
353    
354        public ChunkCoordinates getHomePosition()
355        {
356            return this.homePosition;
357        }
358    
359        public float getMaximumHomeDistance()
360        {
361            return this.maximumHomeDistance;
362        }
363    
364        public void detachHome()
365        {
366            this.maximumHomeDistance = -1.0F;
367        }
368    
369        public boolean hasHome()
370        {
371            return this.maximumHomeDistance != -1.0F;
372        }
373    
374        public void setRevengeTarget(EntityLiving par1EntityLiving)
375        {
376            this.entityLivingToAttack = par1EntityLiving;
377            this.revengeTimer = this.entityLivingToAttack != null ? 60 : 0;
378            ForgeHooks.onLivingSetAttackTarget(this, par1EntityLiving);
379        }
380    
381        protected void entityInit()
382        {
383            this.dataWatcher.addObject(8, Integer.valueOf(this.field_70748_f));
384        }
385    
386        /**
387         * returns true if the entity provided in the argument can be seen. (Raytrace)
388         */
389        public boolean canEntityBeSeen(Entity par1Entity)
390        {
391            return this.worldObj.rayTraceBlocks(Vec3.getVec3Pool().getVecFromPool(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ), Vec3.getVec3Pool().getVecFromPool(par1Entity.posX, par1Entity.posY + (double)par1Entity.getEyeHeight(), par1Entity.posZ)) == null;
392        }
393    
394        @SideOnly(Side.CLIENT)
395    
396        /**
397         * Returns the texture's file path as a String.
398         */
399        public String getTexture()
400        {
401            return this.texture;
402        }
403    
404        /**
405         * Returns true if other Entities should be prevented from moving through this Entity.
406         */
407        public boolean canBeCollidedWith()
408        {
409            return !this.isDead;
410        }
411    
412        /**
413         * Returns true if this entity should push and be pushed by other entities when colliding.
414         */
415        public boolean canBePushed()
416        {
417            return !this.isDead;
418        }
419    
420        public float getEyeHeight()
421        {
422            return this.height * 0.85F;
423        }
424    
425        /**
426         * Get number of ticks, at least during which the living entity will be silent.
427         */
428        public int getTalkInterval()
429        {
430            return 80;
431        }
432    
433        /**
434         * Plays living's sound at its position
435         */
436        public void playLivingSound()
437        {
438            String var1 = this.getLivingSound();
439    
440            if (var1 != null)
441            {
442                this.worldObj.playSoundAtEntity(this, var1, this.getSoundVolume(), this.getSoundPitch());
443            }
444        }
445    
446        /**
447         * Gets called every tick from main Entity class
448         */
449        public void onEntityUpdate()
450        {
451            this.prevSwingProgress = this.swingProgress;
452            super.onEntityUpdate();
453            this.worldObj.theProfiler.startSection("mobBaseTick");
454    
455            if (this.isEntityAlive() && this.rand.nextInt(1000) < this.livingSoundTime++)
456            {
457                this.livingSoundTime = -this.getTalkInterval();
458                this.playLivingSound();
459            }
460    
461            if (this.isEntityAlive() && this.isEntityInsideOpaqueBlock())
462            {
463                this.attackEntityFrom(DamageSource.inWall, 1);
464            }
465    
466            if (this.isImmuneToFire() || this.worldObj.isRemote)
467            {
468                this.extinguish();
469            }
470    
471            if (this.isEntityAlive() && this.isInsideOfMaterial(Material.water) && !this.canBreatheUnderwater() && !this.activePotionsMap.containsKey(Integer.valueOf(Potion.waterBreathing.id)))
472            {
473                this.setAir(this.decreaseAirSupply(this.getAir()));
474    
475                if (this.getAir() == -20)
476                {
477                    this.setAir(0);
478    
479                    for (int var1 = 0; var1 < 8; ++var1)
480                    {
481                        float var2 = this.rand.nextFloat() - this.rand.nextFloat();
482                        float var3 = this.rand.nextFloat() - this.rand.nextFloat();
483                        float var4 = this.rand.nextFloat() - this.rand.nextFloat();
484                        this.worldObj.spawnParticle("bubble", this.posX + (double)var2, this.posY + (double)var3, this.posZ + (double)var4, this.motionX, this.motionY, this.motionZ);
485                    }
486    
487                    this.attackEntityFrom(DamageSource.drown, 2);
488                }
489    
490                this.extinguish();
491            }
492            else
493            {
494                this.setAir(300);
495            }
496    
497            this.prevCameraPitch = this.cameraPitch;
498    
499            if (this.attackTime > 0)
500            {
501                --this.attackTime;
502            }
503    
504            if (this.hurtTime > 0)
505            {
506                --this.hurtTime;
507            }
508    
509            if (this.hurtResistantTime > 0)
510            {
511                --this.hurtResistantTime;
512            }
513    
514            if (this.health <= 0)
515            {
516                this.onDeathUpdate();
517            }
518    
519            if (this.recentlyHit > 0)
520            {
521                --this.recentlyHit;
522            }
523            else
524            {
525                this.attackingPlayer = null;
526            }
527    
528            if (this.lastAttackingEntity != null && !this.lastAttackingEntity.isEntityAlive())
529            {
530                this.lastAttackingEntity = null;
531            }
532    
533            if (this.entityLivingToAttack != null)
534            {
535                if (!this.entityLivingToAttack.isEntityAlive())
536                {
537                    this.setRevengeTarget((EntityLiving)null);
538                }
539                else if (this.revengeTimer > 0)
540                {
541                    --this.revengeTimer;
542                }
543                else
544                {
545                    this.setRevengeTarget((EntityLiving)null);
546                }
547            }
548    
549            this.updatePotionEffects();
550            this.field_70763_ax = this.field_70764_aw;
551            this.prevRenderYawOffset = this.renderYawOffset;
552            this.prevRotationYawHead = this.rotationYawHead;
553            this.prevRotationYaw = this.rotationYaw;
554            this.prevRotationPitch = this.rotationPitch;
555            this.worldObj.theProfiler.endSection();
556        }
557    
558        /**
559         * handles entity death timer, experience orb and particle creation
560         */
561        protected void onDeathUpdate()
562        {
563            ++this.deathTime;
564    
565            if (this.deathTime == 20)
566            {
567                int var1;
568    
569                if (!this.worldObj.isRemote && (this.recentlyHit > 0 || this.isPlayer()) && !this.isChild())
570                {
571                    var1 = this.getExperiencePoints(this.attackingPlayer);
572    
573                    while (var1 > 0)
574                    {
575                        int var2 = EntityXPOrb.getXPSplit(var1);
576                        var1 -= var2;
577                        this.worldObj.spawnEntityInWorld(new EntityXPOrb(this.worldObj, this.posX, this.posY, this.posZ, var2));
578                    }
579                }
580    
581                this.setDead();
582    
583                for (var1 = 0; var1 < 20; ++var1)
584                {
585                    double var8 = this.rand.nextGaussian() * 0.02D;
586                    double var4 = this.rand.nextGaussian() * 0.02D;
587                    double var6 = this.rand.nextGaussian() * 0.02D;
588                    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);
589                }
590            }
591        }
592    
593        /**
594         * Decrements the entity's air supply when underwater
595         */
596        protected int decreaseAirSupply(int par1)
597        {
598            return par1 - 1;
599        }
600    
601        /**
602         * Get the experience points the entity currently has.
603         */
604        protected int getExperiencePoints(EntityPlayer par1EntityPlayer)
605        {
606            return this.experienceValue;
607        }
608    
609        /**
610         * Only use is to identify if class is an instance of player for experience dropping
611         */
612        protected boolean isPlayer()
613        {
614            return false;
615        }
616    
617        /**
618         * Spawns an explosion particle around the Entity's location
619         */
620        public void spawnExplosionParticle()
621        {
622            for (int var1 = 0; var1 < 20; ++var1)
623            {
624                double var2 = this.rand.nextGaussian() * 0.02D;
625                double var4 = this.rand.nextGaussian() * 0.02D;
626                double var6 = this.rand.nextGaussian() * 0.02D;
627                double var8 = 10.0D;
628                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);
629            }
630        }
631    
632        /**
633         * Handles updating while being ridden by an entity
634         */
635        public void updateRidden()
636        {
637            super.updateRidden();
638            this.field_70768_au = this.field_70766_av;
639            this.field_70766_av = 0.0F;
640            this.fallDistance = 0.0F;
641        }
642    
643        @SideOnly(Side.CLIENT)
644    
645        /**
646         * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX,
647         * posY, posZ, yaw, pitch
648         */
649        public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
650        {
651            this.yOffset = 0.0F;
652            this.newPosX = par1;
653            this.newPosY = par3;
654            this.newPosZ = par5;
655            this.newRotationYaw = (double)par7;
656            this.newRotationPitch = (double)par8;
657            this.newPosRotationIncrements = par9;
658        }
659    
660        /**
661         * Called to update the entity's position/logic.
662         */
663        public void onUpdate()
664        {
665            if (ForgeHooks.onLivingUpdate(this))
666            {
667                return;
668            }
669    
670            super.onUpdate();
671    
672            if (this.arrowHitTempCounter > 0)
673            {
674                if (this.arrowHitTimer <= 0)
675                {
676                    this.arrowHitTimer = 60;
677                }
678    
679                --this.arrowHitTimer;
680    
681                if (this.arrowHitTimer <= 0)
682                {
683                    --this.arrowHitTempCounter;
684                }
685            }
686    
687            this.onLivingUpdate();
688            double var1 = this.posX - this.prevPosX;
689            double var3 = this.posZ - this.prevPosZ;
690            float var5 = (float)(var1 * var1 + var3 * var3);
691            float var6 = this.renderYawOffset;
692            float var7 = 0.0F;
693            this.field_70768_au = this.field_70766_av;
694            float var8 = 0.0F;
695    
696            if (var5 > 0.0025000002F)
697            {
698                var8 = 1.0F;
699                var7 = (float)Math.sqrt((double)var5) * 3.0F;
700                var6 = (float)Math.atan2(var3, var1) * 180.0F / (float)Math.PI - 90.0F;
701            }
702    
703            if (this.swingProgress > 0.0F)
704            {
705                var6 = this.rotationYaw;
706            }
707    
708            if (!this.onGround)
709            {
710                var8 = 0.0F;
711            }
712    
713            this.field_70766_av += (var8 - this.field_70766_av) * 0.3F;
714            this.worldObj.theProfiler.startSection("headTurn");
715    
716            if (this.isAIEnabled())
717            {
718                this.bodyHelper.func_75664_a();
719            }
720            else
721            {
722                float var9 = MathHelper.wrapAngleTo180_float(var6 - this.renderYawOffset);
723                this.renderYawOffset += var9 * 0.3F;
724                float var10 = MathHelper.wrapAngleTo180_float(this.rotationYaw - this.renderYawOffset);
725                boolean var11 = var10 < -90.0F || var10 >= 90.0F;
726    
727                if (var10 < -75.0F)
728                {
729                    var10 = -75.0F;
730                }
731    
732                if (var10 >= 75.0F)
733                {
734                    var10 = 75.0F;
735                }
736    
737                this.renderYawOffset = this.rotationYaw - var10;
738    
739                if (var10 * var10 > 2500.0F)
740                {
741                    this.renderYawOffset += var10 * 0.2F;
742                }
743    
744                if (var11)
745                {
746                    var7 *= -1.0F;
747                }
748            }
749    
750            this.worldObj.theProfiler.endSection();
751            this.worldObj.theProfiler.startSection("rangeChecks");
752    
753            while (this.rotationYaw - this.prevRotationYaw < -180.0F)
754            {
755                this.prevRotationYaw -= 360.0F;
756            }
757    
758            while (this.rotationYaw - this.prevRotationYaw >= 180.0F)
759            {
760                this.prevRotationYaw += 360.0F;
761            }
762    
763            while (this.renderYawOffset - this.prevRenderYawOffset < -180.0F)
764            {
765                this.prevRenderYawOffset -= 360.0F;
766            }
767    
768            while (this.renderYawOffset - this.prevRenderYawOffset >= 180.0F)
769            {
770                this.prevRenderYawOffset += 360.0F;
771            }
772    
773            while (this.rotationPitch - this.prevRotationPitch < -180.0F)
774            {
775                this.prevRotationPitch -= 360.0F;
776            }
777    
778            while (this.rotationPitch - this.prevRotationPitch >= 180.0F)
779            {
780                this.prevRotationPitch += 360.0F;
781            }
782    
783            while (this.rotationYawHead - this.prevRotationYawHead < -180.0F)
784            {
785                this.prevRotationYawHead -= 360.0F;
786            }
787    
788            while (this.rotationYawHead - this.prevRotationYawHead >= 180.0F)
789            {
790                this.prevRotationYawHead += 360.0F;
791            }
792    
793            this.worldObj.theProfiler.endSection();
794            this.field_70764_aw += var7;
795        }
796    
797        /**
798         * Heal living entity (param: amount of half-hearts)
799         */
800        public void heal(int par1)
801        {
802            if (this.health > 0)
803            {
804                this.health += par1;
805    
806                if (this.health > this.getMaxHealth())
807                {
808                    this.health = this.getMaxHealth();
809                }
810    
811                this.hurtResistantTime = this.maxHurtResistantTime / 2;
812            }
813        }
814    
815        public abstract int getMaxHealth();
816    
817        public int getHealth()
818        {
819            return this.health;
820        }
821    
822        public void setEntityHealth(int par1)
823        {
824            this.health = par1;
825    
826            if (par1 > this.getMaxHealth())
827            {
828                par1 = this.getMaxHealth();
829            }
830        }
831    
832        /**
833         * Called when the entity is attacked.
834         */
835        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
836        {
837            if (ForgeHooks.onLivingAttack(this, par1DamageSource, par2))
838            {
839                return false;
840            }
841    
842            if (this.worldObj.isRemote)
843            {
844                return false;
845            }
846            else
847            {
848                this.entityAge = 0;
849    
850                if (this.health <= 0)
851                {
852                    return false;
853                }
854                else if (par1DamageSource.fireDamage() && this.isPotionActive(Potion.fireResistance))
855                {
856                    return false;
857                }
858                else
859                {
860                    this.legYaw = 1.5F;
861                    boolean var3 = true;
862    
863                    if ((float)this.hurtResistantTime > (float)this.maxHurtResistantTime / 2.0F)
864                    {
865                        if (par2 <= this.lastDamage)
866                        {
867                            return false;
868                        }
869    
870                        this.damageEntity(par1DamageSource, par2 - this.lastDamage);
871                        this.lastDamage = par2;
872                        var3 = false;
873                    }
874                    else
875                    {
876                        this.lastDamage = par2;
877                        this.prevHealth = this.health;
878                        this.hurtResistantTime = this.maxHurtResistantTime;
879                        this.damageEntity(par1DamageSource, par2);
880                        this.hurtTime = this.maxHurtTime = 10;
881                    }
882    
883                    this.attackedAtYaw = 0.0F;
884                    Entity var4 = par1DamageSource.getEntity();
885    
886                    if (var4 != null)
887                    {
888                        if (var4 instanceof EntityLiving)
889                        {
890                            this.setRevengeTarget((EntityLiving)var4);
891                        }
892    
893                        if (var4 instanceof EntityPlayer)
894                        {
895                            this.recentlyHit = 60;
896                            this.attackingPlayer = (EntityPlayer)var4;
897                        }
898                        else if (var4 instanceof EntityWolf)
899                        {
900                            EntityWolf var5 = (EntityWolf)var4;
901    
902                            if (var5.isTamed())
903                            {
904                                this.recentlyHit = 60;
905                                this.attackingPlayer = null;
906                            }
907                        }
908                    }
909    
910                    if (var3)
911                    {
912                        this.worldObj.setEntityState(this, (byte)2);
913    
914                        if (par1DamageSource != DamageSource.drown && par1DamageSource != DamageSource.field_76375_l)
915                        {
916                            this.setBeenAttacked();
917                        }
918    
919                        if (var4 != null)
920                        {
921                            double var9 = var4.posX - this.posX;
922                            double var7;
923    
924                            for (var7 = var4.posZ - this.posZ; var9 * var9 + var7 * var7 < 1.0E-4D; var7 = (Math.random() - Math.random()) * 0.01D)
925                            {
926                                var9 = (Math.random() - Math.random()) * 0.01D;
927                            }
928    
929                            this.attackedAtYaw = (float)(Math.atan2(var7, var9) * 180.0D / Math.PI) - this.rotationYaw;
930                            this.knockBack(var4, par2, var9, var7);
931                        }
932                        else
933                        {
934                            this.attackedAtYaw = (float)((int)(Math.random() * 2.0D) * 180);
935                        }
936                    }
937    
938                    if (this.health <= 0)
939                    {
940                        if (var3)
941                        {
942                            this.worldObj.playSoundAtEntity(this, this.getDeathSound(), this.getSoundVolume(), this.getSoundPitch());
943                        }
944    
945                        this.onDeath(par1DamageSource);
946                    }
947                    else if (var3)
948                    {
949                        this.worldObj.playSoundAtEntity(this, this.getHurtSound(), this.getSoundVolume(), this.getSoundPitch());
950                    }
951    
952                    return true;
953                }
954            }
955        }
956    
957        /**
958         * Gets the pitch of living sounds in living entities.
959         */
960        private float getSoundPitch()
961        {
962            return this.isChild() ? (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.5F : (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F;
963        }
964    
965        @SideOnly(Side.CLIENT)
966    
967        /**
968         * Setups the entity to do the hurt animation. Only used by packets in multiplayer.
969         */
970        public void performHurtAnimation()
971        {
972            this.hurtTime = this.maxHurtTime = 10;
973            this.attackedAtYaw = 0.0F;
974        }
975    
976        /**
977         * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue
978         */
979        public int getTotalArmorValue()
980        {
981            return 0;
982        }
983    
984        protected void damageArmor(int par1) {}
985    
986        /**
987         * Reduces damage, depending on armor
988         */
989        protected int applyArmorCalculations(DamageSource par1DamageSource, int par2)
990        {
991            if (!par1DamageSource.isUnblockable())
992            {
993                int var3 = 25 - this.getTotalArmorValue();
994                int var4 = par2 * var3 + this.carryoverDamage;
995                this.damageArmor(par2);
996                par2 = var4 / 25;
997                this.carryoverDamage = var4 % 25;
998            }
999    
1000            return par2;
1001        }
1002    
1003        /**
1004         * Reduces damage, depending on potions
1005         */
1006        protected int applyPotionDamageCalculations(DamageSource par1DamageSource, int par2)
1007        {
1008            if (this.isPotionActive(Potion.resistance))
1009            {
1010                int var3 = (this.getActivePotionEffect(Potion.resistance).getAmplifier() + 1) * 5;
1011                int var4 = 25 - var3;
1012                int var5 = par2 * var4 + this.carryoverDamage;
1013                par2 = var5 / 25;
1014                this.carryoverDamage = var5 % 25;
1015            }
1016    
1017            return par2;
1018        }
1019    
1020        /**
1021         * Deals damage to the entity. If its a EntityPlayer then will take damage from the armor first and then health
1022         * second with the reduced value. Args: damageAmount
1023         */
1024        protected void damageEntity(DamageSource par1DamageSource, int par2)
1025        {
1026            par2 = ForgeHooks.onLivingHurt(this, par1DamageSource, par2);
1027            if (par2 <= 0)
1028            {
1029                return;
1030            }
1031    
1032            par2 = this.applyArmorCalculations(par1DamageSource, par2);
1033            par2 = this.applyPotionDamageCalculations(par1DamageSource, par2);
1034            this.health -= par2;
1035        }
1036    
1037        /**
1038         * Returns the volume for the sounds this mob makes.
1039         */
1040        protected float getSoundVolume()
1041        {
1042            return 1.0F;
1043        }
1044    
1045        /**
1046         * Returns the sound this mob makes while it's alive.
1047         */
1048        protected String getLivingSound()
1049        {
1050            return null;
1051        }
1052    
1053        /**
1054         * Returns the sound this mob makes when it is hurt.
1055         */
1056        protected String getHurtSound()
1057        {
1058            return "damage.hurtflesh";
1059        }
1060    
1061        /**
1062         * Returns the sound this mob makes on death.
1063         */
1064        protected String getDeathSound()
1065        {
1066            return "damage.hurtflesh";
1067        }
1068    
1069        /**
1070         * knocks back this entity
1071         */
1072        public void knockBack(Entity par1Entity, int par2, double par3, double par5)
1073        {
1074            this.isAirBorne = true;
1075            float var7 = MathHelper.sqrt_double(par3 * par3 + par5 * par5);
1076            float var8 = 0.4F;
1077            this.motionX /= 2.0D;
1078            this.motionY /= 2.0D;
1079            this.motionZ /= 2.0D;
1080            this.motionX -= par3 / (double)var7 * (double)var8;
1081            this.motionY += (double)var8;
1082            this.motionZ -= par5 / (double)var7 * (double)var8;
1083    
1084            if (this.motionY > 0.4000000059604645D)
1085            {
1086                this.motionY = 0.4000000059604645D;
1087            }
1088        }
1089    
1090        /**
1091         * Called when the mob's health reaches 0.
1092         */
1093        public void onDeath(DamageSource par1DamageSource)
1094        {
1095            if (ForgeHooks.onLivingDeath(this, par1DamageSource))
1096            {
1097                return;
1098            }
1099    
1100            Entity var2 = par1DamageSource.getEntity();
1101    
1102            if (this.scoreValue >= 0 && var2 != null)
1103            {
1104                var2.addToPlayerScore(this, this.scoreValue);
1105            }
1106    
1107            if (var2 != null)
1108            {
1109                var2.onKillEntity(this);
1110            }
1111    
1112            this.dead = true;
1113    
1114            if (!this.worldObj.isRemote)
1115            {
1116                int var3 = 0;
1117    
1118                if (var2 instanceof EntityPlayer)
1119                {
1120                    var3 = EnchantmentHelper.getLootingModifier(((EntityPlayer)var2).inventory);
1121                }
1122    
1123                captureDrops = true;
1124                capturedDrops.clear();
1125                int var4 = 0;
1126    
1127                if (!this.isChild())
1128                {
1129                    this.dropFewItems(this.recentlyHit > 0, var3);
1130    
1131                    if (this.recentlyHit > 0)
1132                    {
1133                        var4 = this.rand.nextInt(200) - var3;
1134    
1135                        if (var4 < 5)
1136                        {
1137                            this.dropRareDrop(var4 <= 0 ? 1 : 0);
1138                        }
1139                    }
1140                }
1141    
1142                captureDrops = false;
1143    
1144                if (!ForgeHooks.onLivingDrops(this, par1DamageSource, capturedDrops, var3, recentlyHit > 0, var4))
1145                {
1146                    for (EntityItem item : capturedDrops)
1147                    {
1148                        worldObj.spawnEntityInWorld(item);
1149                    }
1150                }
1151            }
1152    
1153            this.worldObj.setEntityState(this, (byte)3);
1154        }
1155    
1156        protected void dropRareDrop(int par1) {}
1157    
1158        /**
1159         * Drop 0-2 items of this living's type
1160         */
1161        protected void dropFewItems(boolean par1, int par2)
1162        {
1163            int var3 = this.getDropItemId();
1164    
1165            if (var3 > 0)
1166            {
1167                int var4 = this.rand.nextInt(3);
1168    
1169                if (par2 > 0)
1170                {
1171                    var4 += this.rand.nextInt(par2 + 1);
1172                }
1173    
1174                for (int var5 = 0; var5 < var4; ++var5)
1175                {
1176                    this.dropItem(var3, 1);
1177                }
1178            }
1179        }
1180    
1181        /**
1182         * Returns the item ID for the item the mob drops on death.
1183         */
1184        protected int getDropItemId()
1185        {
1186            return 0;
1187        }
1188    
1189        /**
1190         * Called when the mob is falling. Calculates and applies fall damage.
1191         */
1192        protected void fall(float par1)
1193        {
1194            par1 = ForgeHooks.onLivingFall(this, par1);
1195            if (par1 <= 0)
1196            {
1197                return;
1198            }
1199    
1200            super.fall(par1);
1201            int var2 = MathHelper.ceiling_float_int(par1 - 3.0F);
1202    
1203            if (var2 > 0)
1204            {
1205                if (var2 > 4)
1206                {
1207                    this.worldObj.playSoundAtEntity(this, "damage.fallbig", 1.0F, 1.0F);
1208                }
1209                else
1210                {
1211                    this.worldObj.playSoundAtEntity(this, "damage.fallsmall", 1.0F, 1.0F);
1212                }
1213    
1214                this.attackEntityFrom(DamageSource.fall, var2);
1215                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));
1216    
1217                if (var3 > 0)
1218                {
1219                    StepSound var4 = Block.blocksList[var3].stepSound;
1220                    this.worldObj.playSoundAtEntity(this, var4.getStepSound(), var4.getVolume() * 0.5F, var4.getPitch() * 0.75F);
1221                }
1222            }
1223        }
1224    
1225        /**
1226         * Moves the entity based on the specified heading.  Args: strafe, forward
1227         */
1228        public void moveEntityWithHeading(float par1, float par2)
1229        {
1230            double var9;
1231    
1232            if (this.isInWater() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying))
1233            {
1234                var9 = this.posY;
1235                this.moveFlying(par1, par2, this.isAIEnabled() ? 0.04F : 0.02F);
1236                this.moveEntity(this.motionX, this.motionY, this.motionZ);
1237                this.motionX *= 0.800000011920929D;
1238                this.motionY *= 0.800000011920929D;
1239                this.motionZ *= 0.800000011920929D;
1240                this.motionY -= 0.02D;
1241    
1242                if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ))
1243                {
1244                    this.motionY = 0.30000001192092896D;
1245                }
1246            }
1247            else if (this.handleLavaMovement() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying))
1248            {
1249                var9 = this.posY;
1250                this.moveFlying(par1, par2, 0.02F);
1251                this.moveEntity(this.motionX, this.motionY, this.motionZ);
1252                this.motionX *= 0.5D;
1253                this.motionY *= 0.5D;
1254                this.motionZ *= 0.5D;
1255                this.motionY -= 0.02D;
1256    
1257                if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ))
1258                {
1259                    this.motionY = 0.30000001192092896D;
1260                }
1261            }
1262            else
1263            {
1264                float var3 = 0.91F;
1265    
1266                if (this.onGround)
1267                {
1268                    var3 = 0.54600006F;
1269                    int var4 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ));
1270    
1271                    if (var4 > 0)
1272                    {
1273                        var3 = Block.blocksList[var4].slipperiness * 0.91F;
1274                    }
1275                }
1276    
1277                float var8 = 0.16277136F / (var3 * var3 * var3);
1278                float var5;
1279    
1280                if (this.onGround)
1281                {
1282                    if (this.isAIEnabled())
1283                    {
1284                        var5 = this.getAIMoveSpeed();
1285                    }
1286                    else
1287                    {
1288                        var5 = this.landMovementFactor;
1289                    }
1290    
1291                    var5 *= var8;
1292                }
1293                else
1294                {
1295                    var5 = this.jumpMovementFactor;
1296                }
1297    
1298                this.moveFlying(par1, par2, var5);
1299                var3 = 0.91F;
1300    
1301                if (this.onGround)
1302                {
1303                    var3 = 0.54600006F;
1304                    int var6 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ));
1305    
1306                    if (var6 > 0)
1307                    {
1308                        var3 = Block.blocksList[var6].slipperiness * 0.91F;
1309                    }
1310                }
1311    
1312                if (this.isOnLadder())
1313                {
1314                    float var10 = 0.15F;
1315    
1316                    if (this.motionX < (double)(-var10))
1317                    {
1318                        this.motionX = (double)(-var10);
1319                    }
1320    
1321                    if (this.motionX > (double)var10)
1322                    {
1323                        this.motionX = (double)var10;
1324                    }
1325    
1326                    if (this.motionZ < (double)(-var10))
1327                    {
1328                        this.motionZ = (double)(-var10);
1329                    }
1330    
1331                    if (this.motionZ > (double)var10)
1332                    {
1333                        this.motionZ = (double)var10;
1334                    }
1335    
1336                    this.fallDistance = 0.0F;
1337    
1338                    if (this.motionY < -0.15D)
1339                    {
1340                        this.motionY = -0.15D;
1341                    }
1342    
1343                    boolean var7 = this.isSneaking() && this instanceof EntityPlayer;
1344    
1345                    if (var7 && this.motionY < 0.0D)
1346                    {
1347                        this.motionY = 0.0D;
1348                    }
1349                }
1350    
1351                this.moveEntity(this.motionX, this.motionY, this.motionZ);
1352    
1353                if (this.isCollidedHorizontally && this.isOnLadder())
1354                {
1355                    this.motionY = 0.2D;
1356                }
1357    
1358                this.motionY -= 0.08D;
1359                this.motionY *= 0.9800000190734863D;
1360                this.motionX *= (double)var3;
1361                this.motionZ *= (double)var3;
1362            }
1363    
1364            this.prevLegYaw = this.legYaw;
1365            var9 = this.posX - this.prevPosX;
1366            double var12 = this.posZ - this.prevPosZ;
1367            float var11 = MathHelper.sqrt_double(var9 * var9 + var12 * var12) * 4.0F;
1368    
1369            if (var11 > 1.0F)
1370            {
1371                var11 = 1.0F;
1372            }
1373    
1374            this.legYaw += (var11 - this.legYaw) * 0.4F;
1375            this.field_70754_ba += this.legYaw;
1376        }
1377    
1378        /**
1379         * returns true if this entity is by a ladder, false otherwise
1380         */
1381        public boolean isOnLadder()
1382        {
1383            int var1 = MathHelper.floor_double(this.posX);
1384            int var2 = MathHelper.floor_double(this.boundingBox.minY);
1385            int var3 = MathHelper.floor_double(this.posZ);
1386            int var4 = this.worldObj.getBlockId(var1, var2, var3);
1387            return ForgeHooks.isLivingOnLadder(Block.blocksList[var4], worldObj, var1, var2, var3);
1388        }
1389    
1390        /**
1391         * (abstract) Protected helper method to write subclass entity data to NBT.
1392         */
1393        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
1394        {
1395            par1NBTTagCompound.setShort("Health", (short)this.health);
1396            par1NBTTagCompound.setShort("HurtTime", (short)this.hurtTime);
1397            par1NBTTagCompound.setShort("DeathTime", (short)this.deathTime);
1398            par1NBTTagCompound.setShort("AttackTime", (short)this.attackTime);
1399    
1400            if (!this.activePotionsMap.isEmpty())
1401            {
1402                NBTTagList var2 = new NBTTagList();
1403                Iterator var3 = this.activePotionsMap.values().iterator();
1404    
1405                while (var3.hasNext())
1406                {
1407                    PotionEffect var4 = (PotionEffect)var3.next();
1408                    NBTTagCompound var5 = new NBTTagCompound();
1409                    var5.setByte("Id", (byte)var4.getPotionID());
1410                    var5.setByte("Amplifier", (byte)var4.getAmplifier());
1411                    var5.setInteger("Duration", var4.getDuration());
1412                    var2.appendTag(var5);
1413                }
1414    
1415                par1NBTTagCompound.setTag("ActiveEffects", var2);
1416            }
1417        }
1418    
1419        /**
1420         * (abstract) Protected helper method to read subclass entity data from NBT.
1421         */
1422        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
1423        {
1424            if (this.health < -32768)
1425            {
1426                this.health = -32768;
1427            }
1428    
1429            this.health = par1NBTTagCompound.getShort("Health");
1430    
1431            if (!par1NBTTagCompound.hasKey("Health"))
1432            {
1433                this.health = this.getMaxHealth();
1434            }
1435    
1436            this.hurtTime = par1NBTTagCompound.getShort("HurtTime");
1437            this.deathTime = par1NBTTagCompound.getShort("DeathTime");
1438            this.attackTime = par1NBTTagCompound.getShort("AttackTime");
1439    
1440            if (par1NBTTagCompound.hasKey("ActiveEffects"))
1441            {
1442                NBTTagList var2 = par1NBTTagCompound.getTagList("ActiveEffects");
1443    
1444                for (int var3 = 0; var3 < var2.tagCount(); ++var3)
1445                {
1446                    NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
1447                    byte var5 = var4.getByte("Id");
1448                    byte var6 = var4.getByte("Amplifier");
1449                    int var7 = var4.getInteger("Duration");
1450                    this.activePotionsMap.put(Integer.valueOf(var5), new PotionEffect(var5, var7, var6));
1451                }
1452            }
1453        }
1454    
1455        /**
1456         * Checks whether target entity is alive.
1457         */
1458        public boolean isEntityAlive()
1459        {
1460            return !this.isDead && this.health > 0;
1461        }
1462    
1463        public boolean canBreatheUnderwater()
1464        {
1465            return false;
1466        }
1467    
1468        public void setMoveForward(float par1)
1469        {
1470            this.moveForward = par1;
1471        }
1472    
1473        public void setJumping(boolean par1)
1474        {
1475            this.isJumping = par1;
1476        }
1477    
1478        /**
1479         * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
1480         * use this to react to sunlight and start to burn.
1481         */
1482        public void onLivingUpdate()
1483        {
1484            if (this.jumpTicks > 0)
1485            {
1486                --this.jumpTicks;
1487            }
1488    
1489            if (this.newPosRotationIncrements > 0)
1490            {
1491                double var1 = this.posX + (this.newPosX - this.posX) / (double)this.newPosRotationIncrements;
1492                double var3 = this.posY + (this.newPosY - this.posY) / (double)this.newPosRotationIncrements;
1493                double var5 = this.posZ + (this.newPosZ - this.posZ) / (double)this.newPosRotationIncrements;
1494                double var7 = MathHelper.wrapAngleTo180_double(this.newRotationYaw - (double)this.rotationYaw);
1495                this.rotationYaw = (float)((double)this.rotationYaw + var7 / (double)this.newPosRotationIncrements);
1496                this.rotationPitch = (float)((double)this.rotationPitch + (this.newRotationPitch - (double)this.rotationPitch) / (double)this.newPosRotationIncrements);
1497                --this.newPosRotationIncrements;
1498                this.setPosition(var1, var3, var5);
1499                this.setRotation(this.rotationYaw, this.rotationPitch);
1500            }
1501    
1502            if (Math.abs(this.motionX) < 0.005D)
1503            {
1504                this.motionX = 0.0D;
1505            }
1506    
1507            if (Math.abs(this.motionY) < 0.005D)
1508            {
1509                this.motionY = 0.0D;
1510            }
1511    
1512            if (Math.abs(this.motionZ) < 0.005D)
1513            {
1514                this.motionZ = 0.0D;
1515            }
1516    
1517            this.worldObj.theProfiler.startSection("ai");
1518    
1519            if (this.isMovementBlocked())
1520            {
1521                this.isJumping = false;
1522                this.moveStrafing = 0.0F;
1523                this.moveForward = 0.0F;
1524                this.randomYawVelocity = 0.0F;
1525            }
1526            else if (this.isClientWorld())
1527            {
1528                if (this.isAIEnabled())
1529                {
1530                    this.worldObj.theProfiler.startSection("newAi");
1531                    this.updateAITasks();
1532                    this.worldObj.theProfiler.endSection();
1533                }
1534                else
1535                {
1536                    this.worldObj.theProfiler.startSection("oldAi");
1537                    this.updateEntityActionState();
1538                    this.worldObj.theProfiler.endSection();
1539                    this.rotationYawHead = this.rotationYaw;
1540                }
1541            }
1542    
1543            this.worldObj.theProfiler.endSection();
1544            this.worldObj.theProfiler.startSection("jump");
1545    
1546            if (this.isJumping)
1547            {
1548                if (!this.isInWater() && !this.handleLavaMovement())
1549                {
1550                    if (this.onGround && this.jumpTicks == 0)
1551                    {
1552                        this.jump();
1553                        this.jumpTicks = 10;
1554                    }
1555                }
1556                else
1557                {
1558                    this.motionY += 0.03999999910593033D;
1559                }
1560            }
1561            else
1562            {
1563                this.jumpTicks = 0;
1564            }
1565    
1566            this.worldObj.theProfiler.endSection();
1567            this.worldObj.theProfiler.startSection("travel");
1568            this.moveStrafing *= 0.98F;
1569            this.moveForward *= 0.98F;
1570            this.randomYawVelocity *= 0.9F;
1571            float var9 = this.landMovementFactor;
1572            this.landMovementFactor *= this.getSpeedModifier();
1573            this.moveEntityWithHeading(this.moveStrafing, this.moveForward);
1574            this.landMovementFactor = var9;
1575            this.worldObj.theProfiler.endSection();
1576            this.worldObj.theProfiler.startSection("push");
1577    
1578            if (!this.worldObj.isRemote)
1579            {
1580                List var2 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D));
1581    
1582                if (var2 != null && !var2.isEmpty())
1583                {
1584                    Iterator var10 = var2.iterator();
1585    
1586                    while (var10.hasNext())
1587                    {
1588                        Entity var4 = (Entity)var10.next();
1589    
1590                        if (var4.canBePushed())
1591                        {
1592                            var4.applyEntityCollision(this);
1593                        }
1594                    }
1595                }
1596            }
1597    
1598            this.worldObj.theProfiler.endSection();
1599        }
1600    
1601        /**
1602         * Returns true if the newer Entity AI code should be run
1603         */
1604        protected boolean isAIEnabled()
1605        {
1606            return false;
1607        }
1608    
1609        /**
1610         * Returns whether the entity is in a local (client) world
1611         */
1612        protected boolean isClientWorld()
1613        {
1614            return !this.worldObj.isRemote;
1615        }
1616    
1617        /**
1618         * Dead and sleeping entities cannot move
1619         */
1620        protected boolean isMovementBlocked()
1621        {
1622            return this.health <= 0;
1623        }
1624    
1625        public boolean isBlocking()
1626        {
1627            return false;
1628        }
1629    
1630        /**
1631         * Causes this entity to do an upwards motion (jumping).
1632         */
1633        protected void jump()
1634        {
1635            this.motionY = 0.41999998688697815D;
1636    
1637            if (this.isPotionActive(Potion.jump))
1638            {
1639                this.motionY += (double)((float)(this.getActivePotionEffect(Potion.jump).getAmplifier() + 1) * 0.1F);
1640            }
1641    
1642            if (this.isSprinting())
1643            {
1644                float var1 = this.rotationYaw * 0.017453292F;
1645                this.motionX -= (double)(MathHelper.sin(var1) * 0.2F);
1646                this.motionZ += (double)(MathHelper.cos(var1) * 0.2F);
1647            }
1648    
1649            this.isAirBorne = true;
1650            ForgeHooks.onLivingJump(this);
1651        }
1652    
1653        /**
1654         * Determines if an entity can be despawned, used on idle far away entities
1655         */
1656        protected boolean canDespawn()
1657        {
1658            return true;
1659        }
1660    
1661        /**
1662         * Makes the entity despawn if requirements are reached
1663         */
1664        protected void despawnEntity()
1665        {
1666            EntityPlayer var1 = this.worldObj.getClosestPlayerToEntity(this, -1.0D);
1667    
1668            if (var1 != null)
1669            {
1670                double var2 = var1.posX - this.posX;
1671                double var4 = var1.posY - this.posY;
1672                double var6 = var1.posZ - this.posZ;
1673                double var8 = var2 * var2 + var4 * var4 + var6 * var6;
1674    
1675                if (this.canDespawn() && var8 > 16384.0D)
1676                {
1677                    this.setDead();
1678                }
1679    
1680                if (this.entityAge > 600 && this.rand.nextInt(800) == 0 && var8 > 1024.0D && this.canDespawn())
1681                {
1682                    this.setDead();
1683                }
1684                else if (var8 < 1024.0D)
1685                {
1686                    this.entityAge = 0;
1687                }
1688            }
1689        }
1690    
1691        protected void updateAITasks()
1692        {
1693            ++this.entityAge;
1694            this.worldObj.theProfiler.startSection("checkDespawn");
1695            this.despawnEntity();
1696            this.worldObj.theProfiler.endSection();
1697            this.worldObj.theProfiler.startSection("sensing");
1698            this.senses.clearSensingCache();
1699            this.worldObj.theProfiler.endSection();
1700            this.worldObj.theProfiler.startSection("targetSelector");
1701            this.targetTasks.onUpdateTasks();
1702            this.worldObj.theProfiler.endSection();
1703            this.worldObj.theProfiler.startSection("goalSelector");
1704            this.tasks.onUpdateTasks();
1705            this.worldObj.theProfiler.endSection();
1706            this.worldObj.theProfiler.startSection("navigation");
1707            this.navigator.onUpdateNavigation();
1708            this.worldObj.theProfiler.endSection();
1709            this.worldObj.theProfiler.startSection("mob tick");
1710            this.updateAITick();
1711            this.worldObj.theProfiler.endSection();
1712            this.worldObj.theProfiler.startSection("controls");
1713            this.worldObj.theProfiler.startSection("move");
1714            this.moveHelper.onUpdateMoveHelper();
1715            this.worldObj.theProfiler.endStartSection("look");
1716            this.lookHelper.onUpdateLook();
1717            this.worldObj.theProfiler.endStartSection("jump");
1718            this.jumpHelper.doJump();
1719            this.worldObj.theProfiler.endSection();
1720            this.worldObj.theProfiler.endSection();
1721        }
1722    
1723        /**
1724         * main AI tick function, replaces updateEntityActionState
1725         */
1726        protected void updateAITick() {}
1727    
1728        protected void updateEntityActionState()
1729        {
1730            ++this.entityAge;
1731            this.despawnEntity();
1732            this.moveStrafing = 0.0F;
1733            this.moveForward = 0.0F;
1734            float var1 = 8.0F;
1735    
1736            if (this.rand.nextFloat() < 0.02F)
1737            {
1738                EntityPlayer var2 = this.worldObj.getClosestPlayerToEntity(this, (double)var1);
1739    
1740                if (var2 != null)
1741                {
1742                    this.currentTarget = var2;
1743                    this.numTicksToChaseTarget = 10 + this.rand.nextInt(20);
1744                }
1745                else
1746                {
1747                    this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F;
1748                }
1749            }
1750    
1751            if (this.currentTarget != null)
1752            {
1753                this.faceEntity(this.currentTarget, 10.0F, (float)this.getVerticalFaceSpeed());
1754    
1755                if (this.numTicksToChaseTarget-- <= 0 || this.currentTarget.isDead || this.currentTarget.getDistanceSqToEntity(this) > (double)(var1 * var1))
1756                {
1757                    this.currentTarget = null;
1758                }
1759            }
1760            else
1761            {
1762                if (this.rand.nextFloat() < 0.05F)
1763                {
1764                    this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F;
1765                }
1766    
1767                this.rotationYaw += this.randomYawVelocity;
1768                this.rotationPitch = this.defaultPitch;
1769            }
1770    
1771            boolean var4 = this.isInWater();
1772            boolean var3 = this.handleLavaMovement();
1773    
1774            if (var4 || var3)
1775            {
1776                this.isJumping = this.rand.nextFloat() < 0.8F;
1777            }
1778        }
1779    
1780        /**
1781         * The speed it takes to move the entityliving's rotationPitch through the faceEntity method. This is only currently
1782         * use in wolves.
1783         */
1784        public int getVerticalFaceSpeed()
1785        {
1786            return 40;
1787        }
1788    
1789        /**
1790         * Changes pitch and yaw so that the entity calling the function is facing the entity provided as an argument.
1791         */
1792        public void faceEntity(Entity par1Entity, float par2, float par3)
1793        {
1794            double var4 = par1Entity.posX - this.posX;
1795            double var8 = par1Entity.posZ - this.posZ;
1796            double var6;
1797    
1798            if (par1Entity instanceof EntityLiving)
1799            {
1800                EntityLiving var10 = (EntityLiving)par1Entity;
1801                var6 = this.posY + (double)this.getEyeHeight() - (var10.posY + (double)var10.getEyeHeight());
1802            }
1803            else
1804            {
1805                var6 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) / 2.0D - (this.posY + (double)this.getEyeHeight());
1806            }
1807    
1808            double var14 = (double)MathHelper.sqrt_double(var4 * var4 + var8 * var8);
1809            float var12 = (float)(Math.atan2(var8, var4) * 180.0D / Math.PI) - 90.0F;
1810            float var13 = (float)(-(Math.atan2(var6, var14) * 180.0D / Math.PI));
1811            this.rotationPitch = -this.updateRotation(this.rotationPitch, var13, par3);
1812            this.rotationYaw = this.updateRotation(this.rotationYaw, var12, par2);
1813        }
1814    
1815        /**
1816         * Arguments: current rotation, intended rotation, max increment.
1817         */
1818        private float updateRotation(float par1, float par2, float par3)
1819        {
1820            float var4 = MathHelper.wrapAngleTo180_float(par2 - par1);
1821    
1822            if (var4 > par3)
1823            {
1824                var4 = par3;
1825            }
1826    
1827            if (var4 < -par3)
1828            {
1829                var4 = -par3;
1830            }
1831    
1832            return par1 + var4;
1833        }
1834    
1835        /**
1836         * Checks if the entity's current position is a valid location to spawn this entity.
1837         */
1838        public boolean getCanSpawnHere()
1839        {
1840            return this.worldObj.checkIfAABBIsClear(this.boundingBox) && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox);
1841        }
1842    
1843        /**
1844         * sets the dead flag. Used when you fall off the bottom of the world.
1845         */
1846        protected void kill()
1847        {
1848            this.attackEntityFrom(DamageSource.outOfWorld, 4);
1849        }
1850    
1851        @SideOnly(Side.CLIENT)
1852    
1853        /**
1854         * Returns where in the swing animation the living entity is (from 0 to 1).  Args: partialTickTime
1855         */
1856        public float getSwingProgress(float par1)
1857        {
1858            float var2 = this.swingProgress - this.prevSwingProgress;
1859    
1860            if (var2 < 0.0F)
1861            {
1862                ++var2;
1863            }
1864    
1865            return this.prevSwingProgress + var2 * par1;
1866        }
1867    
1868        @SideOnly(Side.CLIENT)
1869    
1870        /**
1871         * interpolated position vector
1872         */
1873        public Vec3 getPosition(float par1)
1874        {
1875            if (par1 == 1.0F)
1876            {
1877                return Vec3.getVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
1878            }
1879            else
1880            {
1881                double var2 = this.prevPosX + (this.posX - this.prevPosX) * (double)par1;
1882                double var4 = this.prevPosY + (this.posY - this.prevPosY) * (double)par1;
1883                double var6 = this.prevPosZ + (this.posZ - this.prevPosZ) * (double)par1;
1884                return Vec3.getVec3Pool().getVecFromPool(var2, var4, var6);
1885            }
1886        }
1887    
1888        /**
1889         * returns a (normalized) vector of where this entity is looking
1890         */
1891        public Vec3 getLookVec()
1892        {
1893            return this.getLook(1.0F);
1894        }
1895    
1896        /**
1897         * interpolated look vector
1898         */
1899        public Vec3 getLook(float par1)
1900        {
1901            float var2;
1902            float var3;
1903            float var4;
1904            float var5;
1905    
1906            if (par1 == 1.0F)
1907            {
1908                var2 = MathHelper.cos(-this.rotationYaw * 0.017453292F - (float)Math.PI);
1909                var3 = MathHelper.sin(-this.rotationYaw * 0.017453292F - (float)Math.PI);
1910                var4 = -MathHelper.cos(-this.rotationPitch * 0.017453292F);
1911                var5 = MathHelper.sin(-this.rotationPitch * 0.017453292F);
1912                return Vec3.getVec3Pool().getVecFromPool((double)(var3 * var4), (double)var5, (double)(var2 * var4));
1913            }
1914            else
1915            {
1916                var2 = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * par1;
1917                var3 = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * par1;
1918                var4 = MathHelper.cos(-var3 * 0.017453292F - (float)Math.PI);
1919                var5 = MathHelper.sin(-var3 * 0.017453292F - (float)Math.PI);
1920                float var6 = -MathHelper.cos(-var2 * 0.017453292F);
1921                float var7 = MathHelper.sin(-var2 * 0.017453292F);
1922                return Vec3.getVec3Pool().getVecFromPool((double)(var5 * var6), (double)var7, (double)(var4 * var6));
1923            }
1924        }
1925    
1926        @SideOnly(Side.CLIENT)
1927    
1928        /**
1929         * Returns render size modifier
1930         */
1931        public float getRenderSizeModifier()
1932        {
1933            return 1.0F;
1934        }
1935    
1936        @SideOnly(Side.CLIENT)
1937    
1938        /**
1939         * Performs a ray trace for the distance specified and using the partial tick time. Args: distance, partialTickTime
1940         */
1941        public MovingObjectPosition rayTrace(double par1, float par3)
1942        {
1943            Vec3 var4 = this.getPosition(par3);
1944            Vec3 var5 = this.getLook(par3);
1945            Vec3 var6 = var4.addVector(var5.xCoord * par1, var5.yCoord * par1, var5.zCoord * par1);
1946            return this.worldObj.rayTraceBlocks(var4, var6);
1947        }
1948    
1949        /**
1950         * Will return how many at most can spawn in a chunk at once.
1951         */
1952        public int getMaxSpawnedInChunk()
1953        {
1954            return 4;
1955        }
1956    
1957        @SideOnly(Side.CLIENT)
1958    
1959        /**
1960         * Returns the item that this EntityLiving is holding, if any.
1961         */
1962        public ItemStack getHeldItem()
1963        {
1964            return null;
1965        }
1966    
1967        @SideOnly(Side.CLIENT)
1968        public void handleHealthUpdate(byte par1)
1969        {
1970            if (par1 == 2)
1971            {
1972                this.legYaw = 1.5F;
1973                this.hurtResistantTime = this.maxHurtResistantTime;
1974                this.hurtTime = this.maxHurtTime = 10;
1975                this.attackedAtYaw = 0.0F;
1976                this.worldObj.playSoundAtEntity(this, this.getHurtSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
1977                this.attackEntityFrom(DamageSource.generic, 0);
1978            }
1979            else if (par1 == 3)
1980            {
1981                this.worldObj.playSoundAtEntity(this, this.getDeathSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
1982                this.health = 0;
1983                this.onDeath(DamageSource.generic);
1984            }
1985            else
1986            {
1987                super.handleHealthUpdate(par1);
1988            }
1989        }
1990    
1991        /**
1992         * Returns whether player is sleeping or not
1993         */
1994        public boolean isPlayerSleeping()
1995        {
1996            return false;
1997        }
1998    
1999        @SideOnly(Side.CLIENT)
2000    
2001        /**
2002         * Gets the Icon Index of the item currently held
2003         */
2004        public int getItemIcon(ItemStack par1ItemStack, int par2)
2005        {
2006            return par1ItemStack.getIconIndex();
2007        }
2008    
2009        protected void updatePotionEffects()
2010        {
2011            Iterator var1 = this.activePotionsMap.keySet().iterator();
2012    
2013            while (var1.hasNext())
2014            {
2015                Integer var2 = (Integer)var1.next();
2016                PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2);
2017    
2018                if (!var3.onUpdate(this) && !this.worldObj.isRemote)
2019                {
2020                    var1.remove();
2021                    this.onFinishedPotionEffect(var3);
2022                }
2023            }
2024    
2025            int var9;
2026    
2027            if (this.potionsNeedUpdate)
2028            {
2029                if (!this.worldObj.isRemote)
2030                {
2031                    if (this.activePotionsMap.isEmpty())
2032                    {
2033                        this.dataWatcher.updateObject(8, Integer.valueOf(0));
2034                    }
2035                    else
2036                    {
2037                        var9 = PotionHelper.calcPotionLiquidColor(this.activePotionsMap.values());
2038                        this.dataWatcher.updateObject(8, Integer.valueOf(var9));
2039                    }
2040                }
2041    
2042                this.potionsNeedUpdate = false;
2043            }
2044    
2045            if (this.rand.nextBoolean())
2046            {
2047                var9 = this.dataWatcher.getWatchableObjectInt(8);
2048    
2049                if (var9 > 0)
2050                {
2051                    double var10 = (double)(var9 >> 16 & 255) / 255.0D;
2052                    double var5 = (double)(var9 >> 8 & 255) / 255.0D;
2053                    double var7 = (double)(var9 >> 0 & 255) / 255.0D;
2054                    this.worldObj.spawnParticle("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, var10, var5, var7);
2055                }
2056            }
2057        }
2058    
2059        public void clearActivePotions()
2060        {
2061            Iterator var1 = this.activePotionsMap.keySet().iterator();
2062    
2063            while (var1.hasNext())
2064            {
2065                Integer var2 = (Integer)var1.next();
2066                PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2);
2067    
2068                if (!this.worldObj.isRemote)
2069                {
2070                    var1.remove();
2071                    this.onFinishedPotionEffect(var3);
2072                }
2073            }
2074        }
2075    
2076        public Collection getActivePotionEffects()
2077        {
2078            return this.activePotionsMap.values();
2079        }
2080    
2081        public boolean isPotionActive(Potion par1Potion)
2082        {
2083            return this.activePotionsMap.containsKey(Integer.valueOf(par1Potion.id));
2084        }
2085    
2086        /**
2087         * returns the PotionEffect for the supplied Potion if it is active, null otherwise.
2088         */
2089        public PotionEffect getActivePotionEffect(Potion par1Potion)
2090        {
2091            return (PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1Potion.id));
2092        }
2093    
2094        /**
2095         * adds a PotionEffect to the entity
2096         */
2097        public void addPotionEffect(PotionEffect par1PotionEffect)
2098        {
2099            if (this.isPotionApplicable(par1PotionEffect))
2100            {
2101                if (this.activePotionsMap.containsKey(Integer.valueOf(par1PotionEffect.getPotionID())))
2102                {
2103                    ((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID()))).combine(par1PotionEffect);
2104                    this.onChangedPotionEffect((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID())));
2105                }
2106                else
2107                {
2108                    this.activePotionsMap.put(Integer.valueOf(par1PotionEffect.getPotionID()), par1PotionEffect);
2109                    this.onNewPotionEffect(par1PotionEffect);
2110                }
2111            }
2112        }
2113    
2114        public boolean isPotionApplicable(PotionEffect par1PotionEffect)
2115        {
2116            if (this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD)
2117            {
2118                int var2 = par1PotionEffect.getPotionID();
2119    
2120                if (var2 == Potion.regeneration.id || var2 == Potion.poison.id)
2121                {
2122                    return false;
2123                }
2124            }
2125    
2126            return true;
2127        }
2128    
2129        /**
2130         * Returns true if this entity is undead.
2131         */
2132        public boolean isEntityUndead()
2133        {
2134            return this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD;
2135        }
2136    
2137        @SideOnly(Side.CLIENT)
2138    
2139        /**
2140         * input is the potion id to remove from the current active potion effects
2141         */
2142        public void removePotionEffect(int par1)
2143        {
2144            this.activePotionsMap.remove(Integer.valueOf(par1));
2145        }
2146    
2147        protected void onNewPotionEffect(PotionEffect par1PotionEffect)
2148        {
2149            this.potionsNeedUpdate = true;
2150        }
2151    
2152        protected void onChangedPotionEffect(PotionEffect par1PotionEffect)
2153        {
2154            this.potionsNeedUpdate = true;
2155        }
2156    
2157        protected void onFinishedPotionEffect(PotionEffect par1PotionEffect)
2158        {
2159            this.potionsNeedUpdate = true;
2160        }
2161    
2162        /**
2163         * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown
2164         * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities.
2165         */
2166        protected float getSpeedModifier()
2167        {
2168            float var1 = 1.0F;
2169    
2170            if (this.isPotionActive(Potion.moveSpeed))
2171            {
2172                var1 *= 1.0F + 0.2F * (float)(this.getActivePotionEffect(Potion.moveSpeed).getAmplifier() + 1);
2173            }
2174    
2175            if (this.isPotionActive(Potion.moveSlowdown))
2176            {
2177                var1 *= 1.0F - 0.15F * (float)(this.getActivePotionEffect(Potion.moveSlowdown).getAmplifier() + 1);
2178            }
2179    
2180            return var1;
2181        }
2182    
2183        /**
2184         * Move the entity to the coordinates informed, but keep yaw/pitch values.
2185         */
2186        public void setPositionAndUpdate(double par1, double par3, double par5)
2187        {
2188            this.setLocationAndAngles(par1, par3, par5, this.rotationYaw, this.rotationPitch);
2189        }
2190    
2191        /**
2192         * If Animal, checks if the age timer is negative
2193         */
2194        public boolean isChild()
2195        {
2196            return false;
2197        }
2198    
2199        /**
2200         * Get this Entity's EnumCreatureAttribute
2201         */
2202        public EnumCreatureAttribute getCreatureAttribute()
2203        {
2204            return EnumCreatureAttribute.UNDEFINED;
2205        }
2206    
2207        /**
2208         * Renders broken item particles using the given ItemStack
2209         */
2210        public void renderBrokenItemStack(ItemStack par1ItemStack)
2211        {
2212            this.worldObj.playSoundAtEntity(this, "random.break", 0.8F, 0.8F + this.worldObj.rand.nextFloat() * 0.4F);
2213    
2214            for (int var2 = 0; var2 < 5; ++var2)
2215            {
2216                Vec3 var3 = Vec3.getVec3Pool().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D);
2217                var3.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F);
2218                var3.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F);
2219                Vec3 var4 = Vec3.getVec3Pool().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.3D, (double)(-this.rand.nextFloat()) * 0.6D - 0.3D, 0.6D);
2220                var4.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F);
2221                var4.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F);
2222                var4 = var4.addVector(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ);
2223                this.worldObj.spawnParticle("iconcrack_" + par1ItemStack.getItem().shiftedIndex, var4.xCoord, var4.yCoord, var4.zCoord, var3.xCoord, var3.yCoord + 0.05D, var3.zCoord);
2224            }
2225        }
2226    }