001 package net.minecraft.src; 002 003 import java.util.List; 004 005 public abstract class EntityAnimal extends EntityAgeable implements IAnimals 006 { 007 public int inLove; 008 009 /** 010 * This is representation of a counter for reproduction progress. (Note that this is different from the inLove which 011 * represent being in Love-Mode) 012 */ 013 private int breeding = 0; 014 015 public EntityAnimal(World par1World) 016 { 017 super(par1World); 018 } 019 020 /** 021 * main AI tick function, replaces updateEntityActionState 022 */ 023 protected void updateAITick() 024 { 025 if (this.getGrowingAge() != 0) 026 { 027 this.inLove = 0; 028 } 029 030 super.updateAITick(); 031 } 032 033 /** 034 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons 035 * use this to react to sunlight and start to burn. 036 */ 037 public void onLivingUpdate() 038 { 039 super.onLivingUpdate(); 040 041 if (this.getGrowingAge() != 0) 042 { 043 this.inLove = 0; 044 } 045 046 if (this.inLove > 0) 047 { 048 --this.inLove; 049 String var1 = "heart"; 050 051 if (this.inLove % 10 == 0) 052 { 053 double var2 = this.rand.nextGaussian() * 0.02D; 054 double var4 = this.rand.nextGaussian() * 0.02D; 055 double var6 = this.rand.nextGaussian() * 0.02D; 056 this.worldObj.spawnParticle(var1, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, var2, var4, var6); 057 } 058 } 059 else 060 { 061 this.breeding = 0; 062 } 063 } 064 065 /** 066 * Basic mob attack. Default to touch of death in EntityCreature. Overridden by each mob to define their attack. 067 */ 068 protected void attackEntity(Entity par1Entity, float par2) 069 { 070 if (par1Entity instanceof EntityPlayer) 071 { 072 if (par2 < 3.0F) 073 { 074 double var3 = par1Entity.posX - this.posX; 075 double var5 = par1Entity.posZ - this.posZ; 076 this.rotationYaw = (float)(Math.atan2(var5, var3) * 180.0D / Math.PI) - 90.0F; 077 this.hasAttacked = true; 078 } 079 080 EntityPlayer var7 = (EntityPlayer)par1Entity; 081 082 if (var7.getCurrentEquippedItem() == null || !this.isBreedingItem(var7.getCurrentEquippedItem())) 083 { 084 this.entityToAttack = null; 085 } 086 } 087 else if (par1Entity instanceof EntityAnimal) 088 { 089 EntityAnimal var8 = (EntityAnimal)par1Entity; 090 091 if (this.getGrowingAge() > 0 && var8.getGrowingAge() < 0) 092 { 093 if ((double)par2 < 2.5D) 094 { 095 this.hasAttacked = true; 096 } 097 } 098 else if (this.inLove > 0 && var8.inLove > 0) 099 { 100 if (var8.entityToAttack == null) 101 { 102 var8.entityToAttack = this; 103 } 104 105 if (var8.entityToAttack == this && (double)par2 < 3.5D) 106 { 107 ++var8.inLove; 108 ++this.inLove; 109 ++this.breeding; 110 111 if (this.breeding % 4 == 0) 112 { 113 this.worldObj.spawnParticle("heart", this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, 0.0D, 0.0D, 0.0D); 114 } 115 116 if (this.breeding == 60) 117 { 118 this.procreate((EntityAnimal)par1Entity); 119 } 120 } 121 else 122 { 123 this.breeding = 0; 124 } 125 } 126 else 127 { 128 this.breeding = 0; 129 this.entityToAttack = null; 130 } 131 } 132 } 133 134 /** 135 * Creates a baby animal according to the animal type of the target at the actual position and spawns 'love' 136 * particles. 137 */ 138 private void procreate(EntityAnimal par1EntityAnimal) 139 { 140 EntityAgeable var2 = this.func_90011_a(par1EntityAnimal); 141 142 if (var2 != null) 143 { 144 this.setGrowingAge(6000); 145 par1EntityAnimal.setGrowingAge(6000); 146 this.inLove = 0; 147 this.breeding = 0; 148 this.entityToAttack = null; 149 par1EntityAnimal.entityToAttack = null; 150 par1EntityAnimal.breeding = 0; 151 par1EntityAnimal.inLove = 0; 152 var2.setGrowingAge(-24000); 153 var2.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch); 154 155 for (int var3 = 0; var3 < 7; ++var3) 156 { 157 double var4 = this.rand.nextGaussian() * 0.02D; 158 double var6 = this.rand.nextGaussian() * 0.02D; 159 double var8 = this.rand.nextGaussian() * 0.02D; 160 this.worldObj.spawnParticle("heart", this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, var4, var6, var8); 161 } 162 163 this.worldObj.spawnEntityInWorld(var2); 164 } 165 } 166 167 /** 168 * Called when the entity is attacked. 169 */ 170 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 171 { 172 if (this.func_85032_ar()) 173 { 174 return false; 175 } 176 else 177 { 178 this.fleeingTick = 60; 179 this.entityToAttack = null; 180 this.inLove = 0; 181 return super.attackEntityFrom(par1DamageSource, par2); 182 } 183 } 184 185 /** 186 * Takes a coordinate in and returns a weight to determine how likely this creature will try to path to the block. 187 * Args: x, y, z 188 */ 189 public float getBlockPathWeight(int par1, int par2, int par3) 190 { 191 return this.worldObj.getBlockId(par1, par2 - 1, par3) == Block.grass.blockID ? 10.0F : this.worldObj.getLightBrightness(par1, par2, par3) - 0.5F; 192 } 193 194 /** 195 * (abstract) Protected helper method to write subclass entity data to NBT. 196 */ 197 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 198 { 199 super.writeEntityToNBT(par1NBTTagCompound); 200 par1NBTTagCompound.setInteger("InLove", this.inLove); 201 } 202 203 /** 204 * (abstract) Protected helper method to read subclass entity data from NBT. 205 */ 206 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 207 { 208 super.readEntityFromNBT(par1NBTTagCompound); 209 this.inLove = par1NBTTagCompound.getInteger("InLove"); 210 } 211 212 /** 213 * Finds the closest player within 16 blocks to attack, or null if this Entity isn't interested in attacking 214 * (Animals, Spiders at day, peaceful PigZombies). 215 */ 216 protected Entity findPlayerToAttack() 217 { 218 if (this.fleeingTick > 0) 219 { 220 return null; 221 } 222 else 223 { 224 float var1 = 8.0F; 225 List var2; 226 int var3; 227 EntityAnimal var4; 228 229 if (this.inLove > 0) 230 { 231 var2 = this.worldObj.getEntitiesWithinAABB(this.getClass(), this.boundingBox.expand((double)var1, (double)var1, (double)var1)); 232 233 for (var3 = 0; var3 < var2.size(); ++var3) 234 { 235 var4 = (EntityAnimal)var2.get(var3); 236 237 if (var4 != this && var4.inLove > 0) 238 { 239 return var4; 240 } 241 } 242 } 243 else if (this.getGrowingAge() == 0) 244 { 245 var2 = this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, this.boundingBox.expand((double)var1, (double)var1, (double)var1)); 246 247 for (var3 = 0; var3 < var2.size(); ++var3) 248 { 249 EntityPlayer var5 = (EntityPlayer)var2.get(var3); 250 251 if (var5.getCurrentEquippedItem() != null && this.isBreedingItem(var5.getCurrentEquippedItem())) 252 { 253 return var5; 254 } 255 } 256 } 257 else if (this.getGrowingAge() > 0) 258 { 259 var2 = this.worldObj.getEntitiesWithinAABB(this.getClass(), this.boundingBox.expand((double)var1, (double)var1, (double)var1)); 260 261 for (var3 = 0; var3 < var2.size(); ++var3) 262 { 263 var4 = (EntityAnimal)var2.get(var3); 264 265 if (var4 != this && var4.getGrowingAge() < 0) 266 { 267 return var4; 268 } 269 } 270 } 271 272 return null; 273 } 274 } 275 276 /** 277 * Checks if the entity's current position is a valid location to spawn this entity. 278 */ 279 public boolean getCanSpawnHere() 280 { 281 int var1 = MathHelper.floor_double(this.posX); 282 int var2 = MathHelper.floor_double(this.boundingBox.minY); 283 int var3 = MathHelper.floor_double(this.posZ); 284 return this.worldObj.getBlockId(var1, var2 - 1, var3) == Block.grass.blockID && this.worldObj.getFullBlockLightValue(var1, var2, var3) > 8 && super.getCanSpawnHere(); 285 } 286 287 /** 288 * Get number of ticks, at least during which the living entity will be silent. 289 */ 290 public int getTalkInterval() 291 { 292 return 120; 293 } 294 295 /** 296 * Determines if an entity can be despawned, used on idle far away entities 297 */ 298 protected boolean canDespawn() 299 { 300 return false; 301 } 302 303 /** 304 * Get the experience points the entity currently has. 305 */ 306 protected int getExperiencePoints(EntityPlayer par1EntityPlayer) 307 { 308 return 1 + this.worldObj.rand.nextInt(3); 309 } 310 311 /** 312 * Checks if the parameter is an item which this animal can be fed to breed it (wheat, carrots or seeds depending on 313 * the animal type) 314 */ 315 public boolean isBreedingItem(ItemStack par1ItemStack) 316 { 317 return par1ItemStack.itemID == Item.wheat.shiftedIndex; 318 } 319 320 /** 321 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 322 */ 323 public boolean interact(EntityPlayer par1EntityPlayer) 324 { 325 ItemStack var2 = par1EntityPlayer.inventory.getCurrentItem(); 326 327 if (var2 != null && this.isBreedingItem(var2) && this.getGrowingAge() == 0) 328 { 329 if (!par1EntityPlayer.capabilities.isCreativeMode) 330 { 331 --var2.stackSize; 332 333 if (var2.stackSize <= 0) 334 { 335 par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null); 336 } 337 } 338 339 this.inLove = 600; 340 this.entityToAttack = null; 341 342 for (int var3 = 0; var3 < 7; ++var3) 343 { 344 double var4 = this.rand.nextGaussian() * 0.02D; 345 double var6 = this.rand.nextGaussian() * 0.02D; 346 double var8 = this.rand.nextGaussian() * 0.02D; 347 this.worldObj.spawnParticle("heart", this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, var4, var6, var8); 348 } 349 350 return true; 351 } 352 else 353 { 354 return super.interact(par1EntityPlayer); 355 } 356 } 357 358 /** 359 * Returns if the entity is currently in 'love mode'. 360 */ 361 public boolean isInLove() 362 { 363 return this.inLove > 0; 364 } 365 366 public void resetInLove() 367 { 368 this.inLove = 0; 369 } 370 371 /** 372 * Returns true if the mob is currently able to mate with the specified mob. 373 */ 374 public boolean canMateWith(EntityAnimal par1EntityAnimal) 375 { 376 return par1EntityAnimal == this ? false : (par1EntityAnimal.getClass() != this.getClass() ? false : this.isInLove() && par1EntityAnimal.isInLove()); 377 } 378 }