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