001 package net.minecraft.entity.passive; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import net.minecraft.block.Block; 006 import net.minecraft.entity.Entity; 007 import net.minecraft.entity.EntityAgeable; 008 import net.minecraft.entity.ai.EntityAIAvoidEntity; 009 import net.minecraft.entity.ai.EntityAIFollowOwner; 010 import net.minecraft.entity.ai.EntityAILeapAtTarget; 011 import net.minecraft.entity.ai.EntityAIMate; 012 import net.minecraft.entity.ai.EntityAIOcelotAttack; 013 import net.minecraft.entity.ai.EntityAIOcelotSit; 014 import net.minecraft.entity.ai.EntityAISwimming; 015 import net.minecraft.entity.ai.EntityAITargetNonTamed; 016 import net.minecraft.entity.ai.EntityAITempt; 017 import net.minecraft.entity.ai.EntityAIWander; 018 import net.minecraft.entity.ai.EntityAIWatchClosest; 019 import net.minecraft.entity.player.EntityPlayer; 020 import net.minecraft.item.Item; 021 import net.minecraft.item.ItemStack; 022 import net.minecraft.nbt.NBTTagCompound; 023 import net.minecraft.util.DamageSource; 024 import net.minecraft.util.MathHelper; 025 import net.minecraft.world.World; 026 027 public class EntityOcelot extends EntityTameable 028 { 029 /** 030 * The tempt AI task for this mob, used to prevent taming while it is fleeing. 031 */ 032 private EntityAITempt aiTempt; 033 034 public EntityOcelot(World par1World) 035 { 036 super(par1World); 037 this.texture = "/mob/ozelot.png"; 038 this.setSize(0.6F, 0.8F); 039 this.getNavigator().setAvoidsWater(true); 040 this.tasks.addTask(1, new EntityAISwimming(this)); 041 this.tasks.addTask(2, this.aiSit); 042 this.tasks.addTask(3, this.aiTempt = new EntityAITempt(this, 0.18F, Item.fishRaw.shiftedIndex, true)); 043 this.tasks.addTask(4, new EntityAIAvoidEntity(this, EntityPlayer.class, 16.0F, 0.23F, 0.4F)); 044 this.tasks.addTask(5, new EntityAIFollowOwner(this, 0.3F, 10.0F, 5.0F)); 045 this.tasks.addTask(6, new EntityAIOcelotSit(this, 0.4F)); 046 this.tasks.addTask(7, new EntityAILeapAtTarget(this, 0.3F)); 047 this.tasks.addTask(8, new EntityAIOcelotAttack(this)); 048 this.tasks.addTask(9, new EntityAIMate(this, 0.23F)); 049 this.tasks.addTask(10, new EntityAIWander(this, 0.23F)); 050 this.tasks.addTask(11, new EntityAIWatchClosest(this, EntityPlayer.class, 10.0F)); 051 this.targetTasks.addTask(1, new EntityAITargetNonTamed(this, EntityChicken.class, 14.0F, 750, false)); 052 } 053 054 protected void entityInit() 055 { 056 super.entityInit(); 057 this.dataWatcher.addObject(18, Byte.valueOf((byte)0)); 058 } 059 060 /** 061 * main AI tick function, replaces updateEntityActionState 062 */ 063 public void updateAITick() 064 { 065 if (this.getMoveHelper().func_75640_a()) 066 { 067 float var1 = this.getMoveHelper().getSpeed(); 068 069 if (var1 == 0.18F) 070 { 071 this.setSneaking(true); 072 this.setSprinting(false); 073 } 074 else if (var1 == 0.4F) 075 { 076 this.setSneaking(false); 077 this.setSprinting(true); 078 } 079 else 080 { 081 this.setSneaking(false); 082 this.setSprinting(false); 083 } 084 } 085 else 086 { 087 this.setSneaking(false); 088 this.setSprinting(false); 089 } 090 } 091 092 /** 093 * Determines if an entity can be despawned, used on idle far away entities 094 */ 095 protected boolean canDespawn() 096 { 097 return !this.isTamed(); 098 } 099 100 @SideOnly(Side.CLIENT) 101 102 /** 103 * Returns the texture's file path as a String. 104 */ 105 public String getTexture() 106 { 107 switch (this.getTameSkin()) 108 { 109 case 0: 110 return "/mob/ozelot.png"; 111 case 1: 112 return "/mob/cat_black.png"; 113 case 2: 114 return "/mob/cat_red.png"; 115 case 3: 116 return "/mob/cat_siamese.png"; 117 default: 118 return super.getTexture(); 119 } 120 } 121 122 /** 123 * Returns true if the newer Entity AI code should be run 124 */ 125 public boolean isAIEnabled() 126 { 127 return true; 128 } 129 130 public int getMaxHealth() 131 { 132 return 10; 133 } 134 135 /** 136 * Called when the mob is falling. Calculates and applies fall damage. 137 */ 138 protected void fall(float par1) {} 139 140 /** 141 * (abstract) Protected helper method to write subclass entity data to NBT. 142 */ 143 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 144 { 145 super.writeEntityToNBT(par1NBTTagCompound); 146 par1NBTTagCompound.setInteger("CatType", this.getTameSkin()); 147 } 148 149 /** 150 * (abstract) Protected helper method to read subclass entity data from NBT. 151 */ 152 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 153 { 154 super.readEntityFromNBT(par1NBTTagCompound); 155 this.setTameSkin(par1NBTTagCompound.getInteger("CatType")); 156 } 157 158 /** 159 * Returns the sound this mob makes while it's alive. 160 */ 161 protected String getLivingSound() 162 { 163 return this.isTamed() ? (this.isInLove() ? "mob.cat.purr" : (this.rand.nextInt(4) == 0 ? "mob.cat.purreow" : "mob.cat.meow")) : ""; 164 } 165 166 /** 167 * Returns the sound this mob makes when it is hurt. 168 */ 169 protected String getHurtSound() 170 { 171 return "mob.cat.hitt"; 172 } 173 174 /** 175 * Returns the sound this mob makes on death. 176 */ 177 protected String getDeathSound() 178 { 179 return "mob.cat.hitt"; 180 } 181 182 /** 183 * Returns the volume for the sounds this mob makes. 184 */ 185 protected float getSoundVolume() 186 { 187 return 0.4F; 188 } 189 190 /** 191 * Returns the item ID for the item the mob drops on death. 192 */ 193 protected int getDropItemId() 194 { 195 return Item.leather.shiftedIndex; 196 } 197 198 public boolean attackEntityAsMob(Entity par1Entity) 199 { 200 return par1Entity.attackEntityFrom(DamageSource.causeMobDamage(this), 3); 201 } 202 203 /** 204 * Called when the entity is attacked. 205 */ 206 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 207 { 208 if (this.func_85032_ar()) 209 { 210 return false; 211 } 212 else 213 { 214 this.aiSit.setSitting(false); 215 return super.attackEntityFrom(par1DamageSource, par2); 216 } 217 } 218 219 /** 220 * Drop 0-2 items of this living's type 221 */ 222 protected void dropFewItems(boolean par1, int par2) {} 223 224 /** 225 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 226 */ 227 public boolean interact(EntityPlayer par1EntityPlayer) 228 { 229 ItemStack var2 = par1EntityPlayer.inventory.getCurrentItem(); 230 231 if (this.isTamed()) 232 { 233 if (par1EntityPlayer.username.equalsIgnoreCase(this.getOwnerName()) && !this.worldObj.isRemote && !this.isBreedingItem(var2)) 234 { 235 this.aiSit.setSitting(!this.isSitting()); 236 } 237 } 238 else if (this.aiTempt.func_75277_f() && var2 != null && var2.itemID == Item.fishRaw.shiftedIndex && par1EntityPlayer.getDistanceSqToEntity(this) < 9.0D) 239 { 240 if (!par1EntityPlayer.capabilities.isCreativeMode) 241 { 242 --var2.stackSize; 243 } 244 245 if (var2.stackSize <= 0) 246 { 247 par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null); 248 } 249 250 if (!this.worldObj.isRemote) 251 { 252 if (this.rand.nextInt(3) == 0) 253 { 254 this.setTamed(true); 255 this.setTameSkin(1 + this.worldObj.rand.nextInt(3)); 256 this.setOwner(par1EntityPlayer.username); 257 this.playTameEffect(true); 258 this.aiSit.setSitting(true); 259 this.worldObj.setEntityState(this, (byte)7); 260 } 261 else 262 { 263 this.playTameEffect(false); 264 this.worldObj.setEntityState(this, (byte)6); 265 } 266 } 267 268 return true; 269 } 270 271 return super.interact(par1EntityPlayer); 272 } 273 274 /** 275 * This function is used when two same-species animals in 'love mode' breed to generate the new baby animal. 276 */ 277 public EntityOcelot spawnBabyAnimal(EntityAgeable par1EntityAgeable) 278 { 279 EntityOcelot var2 = new EntityOcelot(this.worldObj); 280 281 if (this.isTamed()) 282 { 283 var2.setOwner(this.getOwnerName()); 284 var2.setTamed(true); 285 var2.setTameSkin(this.getTameSkin()); 286 } 287 288 return var2; 289 } 290 291 /** 292 * Checks if the parameter is an item which this animal can be fed to breed it (wheat, carrots or seeds depending on 293 * the animal type) 294 */ 295 public boolean isBreedingItem(ItemStack par1ItemStack) 296 { 297 return par1ItemStack != null && par1ItemStack.itemID == Item.fishRaw.shiftedIndex; 298 } 299 300 /** 301 * Returns true if the mob is currently able to mate with the specified mob. 302 */ 303 public boolean canMateWith(EntityAnimal par1EntityAnimal) 304 { 305 if (par1EntityAnimal == this) 306 { 307 return false; 308 } 309 else if (!this.isTamed()) 310 { 311 return false; 312 } 313 else if (!(par1EntityAnimal instanceof EntityOcelot)) 314 { 315 return false; 316 } 317 else 318 { 319 EntityOcelot var2 = (EntityOcelot)par1EntityAnimal; 320 return !var2.isTamed() ? false : this.isInLove() && var2.isInLove(); 321 } 322 } 323 324 public int getTameSkin() 325 { 326 return this.dataWatcher.getWatchableObjectByte(18); 327 } 328 329 public void setTameSkin(int par1) 330 { 331 this.dataWatcher.updateObject(18, Byte.valueOf((byte)par1)); 332 } 333 334 /** 335 * Checks if the entity's current position is a valid location to spawn this entity. 336 */ 337 public boolean getCanSpawnHere() 338 { 339 if (this.worldObj.rand.nextInt(3) == 0) 340 { 341 return false; 342 } 343 else 344 { 345 if (this.worldObj.checkIfAABBIsClear(this.boundingBox) && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox)) 346 { 347 int var1 = MathHelper.floor_double(this.posX); 348 int var2 = MathHelper.floor_double(this.boundingBox.minY); 349 int var3 = MathHelper.floor_double(this.posZ); 350 351 if (var2 < 63) 352 { 353 return false; 354 } 355 356 int var4 = this.worldObj.getBlockId(var1, var2 - 1, var3); 357 Block block = Block.blocksList[var4]; 358 359 if (var4 == Block.grass.blockID || (block != null && block.isLeaves(worldObj, var1, var2 - 1, var3))) 360 { 361 return true; 362 } 363 } 364 365 return false; 366 } 367 } 368 369 /** 370 * Gets the username of the entity. 371 */ 372 public String getEntityName() 373 { 374 return this.isTamed() ? "entity.Cat.name" : super.getEntityName(); 375 } 376 377 /** 378 * Initialize this creature. 379 */ 380 public void initCreature() 381 { 382 if (this.worldObj.rand.nextInt(7) == 0) 383 { 384 for (int var1 = 0; var1 < 2; ++var1) 385 { 386 EntityOcelot var2 = new EntityOcelot(this.worldObj); 387 var2.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, 0.0F); 388 var2.setGrowingAge(-24000); 389 this.worldObj.spawnEntityInWorld(var2); 390 } 391 } 392 } 393 394 public EntityAgeable func_90011_a(EntityAgeable par1EntityAgeable) 395 { 396 return this.spawnBabyAnimal(par1EntityAgeable); 397 } 398 }