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