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