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.itemID, 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.itemID; 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.isEntityInvulnerable()) 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. @param par1 - Whether this entity has recently been hit by a player. @param 221 * par2 - Level of Looting used to kill this mob. 222 */ 223 protected void dropFewItems(boolean par1, int par2) {} 224 225 /** 226 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 227 */ 228 public boolean interact(EntityPlayer par1EntityPlayer) 229 { 230 ItemStack var2 = par1EntityPlayer.inventory.getCurrentItem(); 231 232 if (this.isTamed()) 233 { 234 if (par1EntityPlayer.username.equalsIgnoreCase(this.getOwnerName()) && !this.worldObj.isRemote && !this.isBreedingItem(var2)) 235 { 236 this.aiSit.setSitting(!this.isSitting()); 237 } 238 } 239 else if (this.aiTempt.func_75277_f() && var2 != null && var2.itemID == Item.fishRaw.itemID && par1EntityPlayer.getDistanceSqToEntity(this) < 9.0D) 240 { 241 if (!par1EntityPlayer.capabilities.isCreativeMode) 242 { 243 --var2.stackSize; 244 } 245 246 if (var2.stackSize <= 0) 247 { 248 par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null); 249 } 250 251 if (!this.worldObj.isRemote) 252 { 253 if (this.rand.nextInt(3) == 0) 254 { 255 this.setTamed(true); 256 this.setTameSkin(1 + this.worldObj.rand.nextInt(3)); 257 this.setOwner(par1EntityPlayer.username); 258 this.playTameEffect(true); 259 this.aiSit.setSitting(true); 260 this.worldObj.setEntityState(this, (byte)7); 261 } 262 else 263 { 264 this.playTameEffect(false); 265 this.worldObj.setEntityState(this, (byte)6); 266 } 267 } 268 269 return true; 270 } 271 272 return super.interact(par1EntityPlayer); 273 } 274 275 /** 276 * This function is used when two same-species animals in 'love mode' breed to generate the new baby animal. 277 */ 278 public EntityOcelot spawnBabyAnimal(EntityAgeable par1EntityAgeable) 279 { 280 EntityOcelot var2 = new EntityOcelot(this.worldObj); 281 282 if (this.isTamed()) 283 { 284 var2.setOwner(this.getOwnerName()); 285 var2.setTamed(true); 286 var2.setTameSkin(this.getTameSkin()); 287 } 288 289 return var2; 290 } 291 292 /** 293 * Checks if the parameter is an item which this animal can be fed to breed it (wheat, carrots or seeds depending on 294 * the animal type) 295 */ 296 public boolean isBreedingItem(ItemStack par1ItemStack) 297 { 298 return par1ItemStack != null && par1ItemStack.itemID == Item.fishRaw.itemID; 299 } 300 301 /** 302 * Returns true if the mob is currently able to mate with the specified mob. 303 */ 304 public boolean canMateWith(EntityAnimal par1EntityAnimal) 305 { 306 if (par1EntityAnimal == this) 307 { 308 return false; 309 } 310 else if (!this.isTamed()) 311 { 312 return false; 313 } 314 else if (!(par1EntityAnimal instanceof EntityOcelot)) 315 { 316 return false; 317 } 318 else 319 { 320 EntityOcelot var2 = (EntityOcelot)par1EntityAnimal; 321 return !var2.isTamed() ? false : this.isInLove() && var2.isInLove(); 322 } 323 } 324 325 public int getTameSkin() 326 { 327 return this.dataWatcher.getWatchableObjectByte(18); 328 } 329 330 public void setTameSkin(int par1) 331 { 332 this.dataWatcher.updateObject(18, Byte.valueOf((byte)par1)); 333 } 334 335 /** 336 * Checks if the entity's current position is a valid location to spawn this entity. 337 */ 338 public boolean getCanSpawnHere() 339 { 340 if (this.worldObj.rand.nextInt(3) == 0) 341 { 342 return false; 343 } 344 else 345 { 346 if (this.worldObj.checkIfAABBIsClear(this.boundingBox) && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox)) 347 { 348 int var1 = MathHelper.floor_double(this.posX); 349 int var2 = MathHelper.floor_double(this.boundingBox.minY); 350 int var3 = MathHelper.floor_double(this.posZ); 351 352 if (var2 < 63) 353 { 354 return false; 355 } 356 357 int var4 = this.worldObj.getBlockId(var1, var2 - 1, var3); 358 Block block = Block.blocksList[var4]; 359 360 if (var4 == Block.grass.blockID || (block != null && block.isLeaves(worldObj, var1, var2 - 1, var3))) 361 { 362 return true; 363 } 364 } 365 366 return false; 367 } 368 } 369 370 /** 371 * Gets the username of the entity. 372 */ 373 public String getEntityName() 374 { 375 return this.isTamed() ? "entity.Cat.name" : super.getEntityName(); 376 } 377 378 /** 379 * Initialize this creature. 380 */ 381 public void initCreature() 382 { 383 if (this.worldObj.rand.nextInt(7) == 0) 384 { 385 for (int var1 = 0; var1 < 2; ++var1) 386 { 387 EntityOcelot var2 = new EntityOcelot(this.worldObj); 388 var2.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, 0.0F); 389 var2.setGrowingAge(-24000); 390 this.worldObj.spawnEntityInWorld(var2); 391 } 392 } 393 } 394 395 public EntityAgeable createChild(EntityAgeable par1EntityAgeable) 396 { 397 return this.spawnBabyAnimal(par1EntityAgeable); 398 } 399 }