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