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