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 }