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