001 package net.minecraft.entity; 002 003 import net.minecraft.pathfinding.PathEntity; 004 import net.minecraft.util.MathHelper; 005 import net.minecraft.util.Vec3; 006 import net.minecraft.world.World; 007 008 public abstract class EntityCreature extends EntityLiving 009 { 010 private PathEntity pathToEntity; 011 012 /** The Entity this EntityCreature is set to attack. */ 013 protected Entity entityToAttack; 014 015 /** 016 * returns true if a creature has attacked recently only used for creepers and skeletons 017 */ 018 protected boolean hasAttacked = false; 019 020 /** Used to make a creature speed up and wander away when hit. */ 021 protected int fleeingTick = 0; 022 023 public EntityCreature(World par1World) 024 { 025 super(par1World); 026 } 027 028 /** 029 * Disables a mob's ability to move on its own while true. 030 */ 031 protected boolean isMovementCeased() 032 { 033 return false; 034 } 035 036 protected void updateEntityActionState() 037 { 038 this.worldObj.theProfiler.startSection("ai"); 039 040 if (this.fleeingTick > 0) 041 { 042 --this.fleeingTick; 043 } 044 045 this.hasAttacked = this.isMovementCeased(); 046 float var1 = 16.0F; 047 048 if (this.entityToAttack == null) 049 { 050 this.entityToAttack = this.findPlayerToAttack(); 051 052 if (this.entityToAttack != null) 053 { 054 this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, var1, true, false, false, true); 055 } 056 } 057 else if (this.entityToAttack.isEntityAlive()) 058 { 059 float var2 = this.entityToAttack.getDistanceToEntity(this); 060 061 if (this.canEntityBeSeen(this.entityToAttack)) 062 { 063 this.attackEntity(this.entityToAttack, var2); 064 } 065 } 066 else 067 { 068 this.entityToAttack = null; 069 } 070 071 this.worldObj.theProfiler.endSection(); 072 073 if (!this.hasAttacked && this.entityToAttack != null && (this.pathToEntity == null || this.rand.nextInt(20) == 0)) 074 { 075 this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, var1, true, false, false, true); 076 } 077 else if (!this.hasAttacked && (this.pathToEntity == null && this.rand.nextInt(180) == 0 || this.rand.nextInt(120) == 0 || this.fleeingTick > 0) && this.entityAge < 100) 078 { 079 this.updateWanderPath(); 080 } 081 082 int var21 = MathHelper.floor_double(this.boundingBox.minY + 0.5D); 083 boolean var3 = this.isInWater(); 084 boolean var4 = this.handleLavaMovement(); 085 this.rotationPitch = 0.0F; 086 087 if (this.pathToEntity != null && this.rand.nextInt(100) != 0) 088 { 089 this.worldObj.theProfiler.startSection("followpath"); 090 Vec3 var5 = this.pathToEntity.getPosition(this); 091 double var6 = (double)(this.width * 2.0F); 092 093 while (var5 != null && var5.squareDistanceTo(this.posX, var5.yCoord, this.posZ) < var6 * var6) 094 { 095 this.pathToEntity.incrementPathIndex(); 096 097 if (this.pathToEntity.isFinished()) 098 { 099 var5 = null; 100 this.pathToEntity = null; 101 } 102 else 103 { 104 var5 = this.pathToEntity.getPosition(this); 105 } 106 } 107 108 this.isJumping = false; 109 110 if (var5 != null) 111 { 112 double var8 = var5.xCoord - this.posX; 113 double var10 = var5.zCoord - this.posZ; 114 double var12 = var5.yCoord - (double)var21; 115 float var14 = (float)(Math.atan2(var10, var8) * 180.0D / Math.PI) - 90.0F; 116 float var15 = MathHelper.wrapAngleTo180_float(var14 - this.rotationYaw); 117 this.moveForward = this.moveSpeed; 118 119 if (var15 > 30.0F) 120 { 121 var15 = 30.0F; 122 } 123 124 if (var15 < -30.0F) 125 { 126 var15 = -30.0F; 127 } 128 129 this.rotationYaw += var15; 130 131 if (this.hasAttacked && this.entityToAttack != null) 132 { 133 double var16 = this.entityToAttack.posX - this.posX; 134 double var18 = this.entityToAttack.posZ - this.posZ; 135 float var20 = this.rotationYaw; 136 this.rotationYaw = (float)(Math.atan2(var18, var16) * 180.0D / Math.PI) - 90.0F; 137 var15 = (var20 - this.rotationYaw + 90.0F) * (float)Math.PI / 180.0F; 138 this.moveStrafing = -MathHelper.sin(var15) * this.moveForward * 1.0F; 139 this.moveForward = MathHelper.cos(var15) * this.moveForward * 1.0F; 140 } 141 142 if (var12 > 0.0D) 143 { 144 this.isJumping = true; 145 } 146 } 147 148 if (this.entityToAttack != null) 149 { 150 this.faceEntity(this.entityToAttack, 30.0F, 30.0F); 151 } 152 153 if (this.isCollidedHorizontally && !this.hasPath()) 154 { 155 this.isJumping = true; 156 } 157 158 if (this.rand.nextFloat() < 0.8F && (var3 || var4)) 159 { 160 this.isJumping = true; 161 } 162 163 this.worldObj.theProfiler.endSection(); 164 } 165 else 166 { 167 super.updateEntityActionState(); 168 this.pathToEntity = null; 169 } 170 } 171 172 /** 173 * Time remaining during which the Animal is sped up and flees. 174 */ 175 protected void updateWanderPath() 176 { 177 this.worldObj.theProfiler.startSection("stroll"); 178 boolean var1 = false; 179 int var2 = -1; 180 int var3 = -1; 181 int var4 = -1; 182 float var5 = -99999.0F; 183 184 for (int var6 = 0; var6 < 10; ++var6) 185 { 186 int var7 = MathHelper.floor_double(this.posX + (double)this.rand.nextInt(13) - 6.0D); 187 int var8 = MathHelper.floor_double(this.posY + (double)this.rand.nextInt(7) - 3.0D); 188 int var9 = MathHelper.floor_double(this.posZ + (double)this.rand.nextInt(13) - 6.0D); 189 float var10 = this.getBlockPathWeight(var7, var8, var9); 190 191 if (var10 > var5) 192 { 193 var5 = var10; 194 var2 = var7; 195 var3 = var8; 196 var4 = var9; 197 var1 = true; 198 } 199 } 200 201 if (var1) 202 { 203 this.pathToEntity = this.worldObj.getEntityPathToXYZ(this, var2, var3, var4, 10.0F, true, false, false, true); 204 } 205 206 this.worldObj.theProfiler.endSection(); 207 } 208 209 /** 210 * Basic mob attack. Default to touch of death in EntityCreature. Overridden by each mob to define their attack. 211 */ 212 protected void attackEntity(Entity par1Entity, float par2) {} 213 214 /** 215 * Takes a coordinate in and returns a weight to determine how likely this creature will try to path to the block. 216 * Args: x, y, z 217 */ 218 public float getBlockPathWeight(int par1, int par2, int par3) 219 { 220 return 0.0F; 221 } 222 223 /** 224 * Finds the closest player within 16 blocks to attack, or null if this Entity isn't interested in attacking 225 * (Animals, Spiders at day, peaceful PigZombies). 226 */ 227 protected Entity findPlayerToAttack() 228 { 229 return null; 230 } 231 232 /** 233 * Checks if the entity's current position is a valid location to spawn this entity. 234 */ 235 public boolean getCanSpawnHere() 236 { 237 int var1 = MathHelper.floor_double(this.posX); 238 int var2 = MathHelper.floor_double(this.boundingBox.minY); 239 int var3 = MathHelper.floor_double(this.posZ); 240 return super.getCanSpawnHere() && this.getBlockPathWeight(var1, var2, var3) >= 0.0F; 241 } 242 243 /** 244 * Returns true if entity has a path to follow 245 */ 246 public boolean hasPath() 247 { 248 return this.pathToEntity != null; 249 } 250 251 /** 252 * sets the Entities walk path in EntityCreature 253 */ 254 public void setPathToEntity(PathEntity par1PathEntity) 255 { 256 this.pathToEntity = par1PathEntity; 257 } 258 259 /** 260 * Returns current entities target 261 */ 262 public Entity getEntityToAttack() 263 { 264 return this.entityToAttack; 265 } 266 267 /** 268 * Sets the entity which is to be attacked. 269 */ 270 public void setTarget(Entity par1Entity) 271 { 272 this.entityToAttack = par1Entity; 273 } 274 275 /** 276 * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown 277 * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities. 278 */ 279 public float getSpeedModifier() 280 { 281 float var1 = super.getSpeedModifier(); 282 283 if (this.fleeingTick > 0 && !this.isAIEnabled()) 284 { 285 var1 *= 2.0F; 286 } 287 288 return var1; 289 } 290 }