package net.minecraft.entity; import java.util.UUID; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.entity.passive.EntityTameable; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.pathfinding.PathEntity; import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.World; public abstract class EntityCreature extends EntityLiving { public static final UUID field_110179_h = UUID.fromString("E199AD21-BA8A-4C53-8D13-6182D5C69D3A"); public static final AttributeModifier field_110181_i = (new AttributeModifier(field_110179_h, "Fleeing speed bonus", 2.0D, 2)).setSaved(false); private PathEntity pathToEntity; /** The Entity this EntityCreature is set to attack. */ protected Entity entityToAttack; /** returns true if a creature has attacked recently only used for creepers and skeletons */ protected boolean hasAttacked; /** Used to make a creature speed up and wander away when hit. */ protected int fleeingTick; private ChunkCoordinates homePosition = new ChunkCoordinates(0, 0, 0); /** If -1 there is no maximum distance */ private float maximumHomeDistance = -1.0F; private EntityAIBase aiBase = new EntityAIMoveTowardsRestriction(this, 1.0D); private boolean field_110180_bt; private static final String __OBFID = "CL_00001558"; public EntityCreature(World p_i1602_1_) { super(p_i1602_1_); } /** * Disables a mob's ability to move on its own while true. */ protected boolean isMovementCeased() { return false; } protected void updateEntityActionState() { this.worldObj.theProfiler.startSection("ai"); if (this.fleeingTick > 0 && --this.fleeingTick == 0) { IAttributeInstance iattributeinstance = this.getEntityAttribute(SharedMonsterAttributes.movementSpeed); iattributeinstance.removeModifier(field_110181_i); } this.hasAttacked = this.isMovementCeased(); float f4 = 16.0F; if (this.entityToAttack == null) { this.entityToAttack = this.findPlayerToAttack(); if (this.entityToAttack != null) { this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, f4, true, false, false, true); } } else if (this.entityToAttack.isEntityAlive()) { float f = this.entityToAttack.getDistanceToEntity(this); if (this.canEntityBeSeen(this.entityToAttack)) { this.attackEntity(this.entityToAttack, f); } } else { this.entityToAttack = null; } if (this.entityToAttack instanceof EntityPlayerMP && ((EntityPlayerMP)this.entityToAttack).theItemInWorldManager.isCreative()) { this.entityToAttack = null; } this.worldObj.theProfiler.endSection(); if (!this.hasAttacked && this.entityToAttack != null && (this.pathToEntity == null || this.rand.nextInt(20) == 0)) { this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, f4, true, false, false, true); } else if (!this.hasAttacked && (this.pathToEntity == null && this.rand.nextInt(180) == 0 || this.rand.nextInt(120) == 0 || this.fleeingTick > 0) && this.entityAge < 100) { this.updateWanderPath(); } int i = MathHelper.floor_double(this.boundingBox.minY + 0.5D); boolean flag = this.isInWater(); boolean flag1 = this.handleLavaMovement(); this.rotationPitch = 0.0F; if (this.pathToEntity != null && this.rand.nextInt(100) != 0) { this.worldObj.theProfiler.startSection("followpath"); Vec3 vec3 = this.pathToEntity.getPosition(this); double d0 = (double)(this.width * 2.0F); while (vec3 != null && vec3.squareDistanceTo(this.posX, vec3.yCoord, this.posZ) < d0 * d0) { this.pathToEntity.incrementPathIndex(); if (this.pathToEntity.isFinished()) { vec3 = null; this.pathToEntity = null; } else { vec3 = this.pathToEntity.getPosition(this); } } this.isJumping = false; if (vec3 != null) { double d1 = vec3.xCoord - this.posX; double d2 = vec3.zCoord - this.posZ; double d3 = vec3.yCoord - (double)i; float f1 = (float)(Math.atan2(d2, d1) * 180.0D / Math.PI) - 90.0F; float f2 = MathHelper.wrapAngleTo180_float(f1 - this.rotationYaw); this.moveForward = (float)this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).getAttributeValue(); if (f2 > 30.0F) { f2 = 30.0F; } if (f2 < -30.0F) { f2 = -30.0F; } this.rotationYaw += f2; if (this.hasAttacked && this.entityToAttack != null) { double d4 = this.entityToAttack.posX - this.posX; double d5 = this.entityToAttack.posZ - this.posZ; float f3 = this.rotationYaw; this.rotationYaw = (float)(Math.atan2(d5, d4) * 180.0D / Math.PI) - 90.0F; f2 = (f3 - this.rotationYaw + 90.0F) * (float)Math.PI / 180.0F; this.moveStrafing = -MathHelper.sin(f2) * this.moveForward * 1.0F; this.moveForward = MathHelper.cos(f2) * this.moveForward * 1.0F; } if (d3 > 0.0D) { this.isJumping = true; } } if (this.entityToAttack != null) { this.faceEntity(this.entityToAttack, 30.0F, 30.0F); } if (this.isCollidedHorizontally && !this.hasPath()) { this.isJumping = true; } if (this.rand.nextFloat() < 0.8F && (flag || flag1)) { this.isJumping = true; } this.worldObj.theProfiler.endSection(); } else { super.updateEntityActionState(); this.pathToEntity = null; } } /** * Time remaining during which the Animal is sped up and flees. */ protected void updateWanderPath() { this.worldObj.theProfiler.startSection("stroll"); boolean flag = false; int i = -1; int j = -1; int k = -1; float f = -99999.0F; for (int l = 0; l < 10; ++l) { int i1 = MathHelper.floor_double(this.posX + (double)this.rand.nextInt(13) - 6.0D); int j1 = MathHelper.floor_double(this.posY + (double)this.rand.nextInt(7) - 3.0D); int k1 = MathHelper.floor_double(this.posZ + (double)this.rand.nextInt(13) - 6.0D); float f1 = this.getBlockPathWeight(i1, j1, k1); if (f1 > f) { f = f1; i = i1; j = j1; k = k1; flag = true; } } if (flag) { this.pathToEntity = this.worldObj.getEntityPathToXYZ(this, i, j, k, 10.0F, true, false, false, true); } this.worldObj.theProfiler.endSection(); } /** * Basic mob attack. Default to touch of death in EntityCreature. Overridden by each mob to define their attack. */ protected void attackEntity(Entity p_70785_1_, float p_70785_2_) {} /** * Takes a coordinate in and returns a weight to determine how likely this creature will try to path to the block. * Args: x, y, z */ public float getBlockPathWeight(int p_70783_1_, int p_70783_2_, int p_70783_3_) { return 0.0F; } /** * Finds the closest player within 16 blocks to attack, or null if this Entity isn't interested in attacking * (Animals, Spiders at day, peaceful PigZombies). */ protected Entity findPlayerToAttack() { return null; } /** * Checks if the entity's current position is a valid location to spawn this entity. */ public boolean getCanSpawnHere() { int i = MathHelper.floor_double(this.posX); int j = MathHelper.floor_double(this.boundingBox.minY); int k = MathHelper.floor_double(this.posZ); return super.getCanSpawnHere() && this.getBlockPathWeight(i, j, k) >= 0.0F; } /** * if the entity got a PathEntity it returns true, else false */ public boolean hasPath() { return this.pathToEntity != null; } /** * sets the pathToEntity */ public void setPathToEntity(PathEntity p_70778_1_) { this.pathToEntity = p_70778_1_; } /** * returns the target Entity */ public Entity getEntityToAttack() { return this.entityToAttack; } /** * Sets the entity which is to be attacked. */ public void setTarget(Entity p_70784_1_) { this.entityToAttack = p_70784_1_; } public boolean isWithinHomeDistanceCurrentPosition() { return this.isWithinHomeDistance(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)); } public boolean isWithinHomeDistance(int p_110176_1_, int p_110176_2_, int p_110176_3_) { return this.maximumHomeDistance == -1.0F ? true : this.homePosition.getDistanceSquared(p_110176_1_, p_110176_2_, p_110176_3_) < this.maximumHomeDistance * this.maximumHomeDistance; } public void setHomeArea(int p_110171_1_, int p_110171_2_, int p_110171_3_, int p_110171_4_) { this.homePosition.set(p_110171_1_, p_110171_2_, p_110171_3_); this.maximumHomeDistance = (float)p_110171_4_; } /** * Returns the chunk coordinate object of the home position. */ public ChunkCoordinates getHomePosition() { return this.homePosition; } public float getMaximumHomeDistance() { return this.maximumHomeDistance; } public void detachHome() { this.maximumHomeDistance = -1.0F; } /** * Returns whether a home area is defined for this entity. */ public boolean hasHome() { return this.maximumHomeDistance != -1.0F; } /** * Applies logic related to leashes, for example dragging the entity or breaking the leash. */ protected void updateLeashedState() { super.updateLeashedState(); if (this.getLeashed() && this.getLeashedToEntity() != null && this.getLeashedToEntity().worldObj == this.worldObj) { Entity entity = this.getLeashedToEntity(); this.setHomeArea((int)entity.posX, (int)entity.posY, (int)entity.posZ, 5); float f = this.getDistanceToEntity(entity); if (this instanceof EntityTameable && ((EntityTameable)this).isSitting()) { if (f > 10.0F) { this.clearLeashed(true, true); } return; } if (!this.field_110180_bt) { this.tasks.addTask(2, this.aiBase); this.getNavigator().setAvoidsWater(false); this.field_110180_bt = true; } this.func_142017_o(f); if (f > 4.0F) { this.getNavigator().tryMoveToEntityLiving(entity, 1.0D); } if (f > 6.0F) { double d0 = (entity.posX - this.posX) / (double)f; double d1 = (entity.posY - this.posY) / (double)f; double d2 = (entity.posZ - this.posZ) / (double)f; this.motionX += d0 * Math.abs(d0) * 0.4D; this.motionY += d1 * Math.abs(d1) * 0.4D; this.motionZ += d2 * Math.abs(d2) * 0.4D; } if (f > 10.0F) { this.clearLeashed(true, true); } } else if (!this.getLeashed() && this.field_110180_bt) { this.field_110180_bt = false; this.tasks.removeTask(this.aiBase); this.getNavigator().setAvoidsWater(true); this.detachHome(); } } protected void func_142017_o(float p_142017_1_) {} }