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