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