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