001 package net.minecraft.entity.passive;
002
003 import cpw.mods.fml.relauncher.Side;
004 import cpw.mods.fml.relauncher.SideOnly;
005
006 import java.util.ArrayList;
007 import java.util.Random;
008 import net.minecraft.block.Block;
009 import net.minecraft.entity.EntityAgeable;
010 import net.minecraft.entity.ai.EntityAIEatGrass;
011 import net.minecraft.entity.ai.EntityAIFollowParent;
012 import net.minecraft.entity.ai.EntityAILookIdle;
013 import net.minecraft.entity.ai.EntityAIMate;
014 import net.minecraft.entity.ai.EntityAIPanic;
015 import net.minecraft.entity.ai.EntityAISwimming;
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.item.EntityItem;
020 import net.minecraft.entity.player.EntityPlayer;
021 import net.minecraft.inventory.InventoryCrafting;
022 import net.minecraft.item.Item;
023 import net.minecraft.item.ItemStack;
024 import net.minecraft.item.crafting.CraftingManager;
025 import net.minecraft.nbt.NBTTagCompound;
026 import net.minecraft.util.MathHelper;
027 import net.minecraft.world.World;
028
029 import net.minecraftforge.common.IShearable;
030
031 public class EntitySheep extends EntityAnimal implements IShearable
032 {
033 private final InventoryCrafting field_90016_e = new InventoryCrafting(new ContainerSheep(this), 2, 1);
034
035 /**
036 * Holds the RGB table of the sheep colors - in OpenGL glColor3f values - used to render the sheep colored fleece.
037 */
038 public static final float[][] fleeceColorTable = new float[][] {{1.0F, 1.0F, 1.0F}, {0.85F, 0.5F, 0.2F}, {0.7F, 0.3F, 0.85F}, {0.4F, 0.6F, 0.85F}, {0.9F, 0.9F, 0.2F}, {0.5F, 0.8F, 0.1F}, {0.95F, 0.5F, 0.65F}, {0.3F, 0.3F, 0.3F}, {0.6F, 0.6F, 0.6F}, {0.3F, 0.5F, 0.6F}, {0.5F, 0.25F, 0.7F}, {0.2F, 0.3F, 0.7F}, {0.4F, 0.3F, 0.2F}, {0.4F, 0.5F, 0.2F}, {0.6F, 0.2F, 0.2F}, {0.1F, 0.1F, 0.1F}};
039
040 /**
041 * Used to control movement as well as wool regrowth. Set to 40 on handleHealthUpdate and counts down with each
042 * tick.
043 */
044 private int sheepTimer;
045
046 /** The eat grass AI task for this mob. */
047 private EntityAIEatGrass aiEatGrass = new EntityAIEatGrass(this);
048
049 public EntitySheep(World par1World)
050 {
051 super(par1World);
052 this.texture = "/mob/sheep.png";
053 this.setSize(0.9F, 1.3F);
054 float var2 = 0.23F;
055 this.getNavigator().setAvoidsWater(true);
056 this.tasks.addTask(0, new EntityAISwimming(this));
057 this.tasks.addTask(1, new EntityAIPanic(this, 0.38F));
058 this.tasks.addTask(2, new EntityAIMate(this, var2));
059 this.tasks.addTask(3, new EntityAITempt(this, 0.25F, Item.wheat.itemID, false));
060 this.tasks.addTask(4, new EntityAIFollowParent(this, 0.25F));
061 this.tasks.addTask(5, this.aiEatGrass);
062 this.tasks.addTask(6, new EntityAIWander(this, var2));
063 this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
064 this.tasks.addTask(8, new EntityAILookIdle(this));
065 this.field_90016_e.setInventorySlotContents(0, new ItemStack(Item.dyePowder, 1, 0));
066 this.field_90016_e.setInventorySlotContents(1, new ItemStack(Item.dyePowder, 1, 0));
067 }
068
069 /**
070 * Returns true if the newer Entity AI code should be run
071 */
072 protected boolean isAIEnabled()
073 {
074 return true;
075 }
076
077 protected void updateAITasks()
078 {
079 this.sheepTimer = this.aiEatGrass.getEatGrassTick();
080 super.updateAITasks();
081 }
082
083 /**
084 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
085 * use this to react to sunlight and start to burn.
086 */
087 public void onLivingUpdate()
088 {
089 if (this.worldObj.isRemote)
090 {
091 this.sheepTimer = Math.max(0, this.sheepTimer - 1);
092 }
093
094 super.onLivingUpdate();
095 }
096
097 public int getMaxHealth()
098 {
099 return 8;
100 }
101
102 protected void entityInit()
103 {
104 super.entityInit();
105 this.dataWatcher.addObject(16, new Byte((byte)0));
106 }
107
108 /**
109 * Drop 0-2 items of this living's type. @param par1 - Whether this entity has recently been hit by a player. @param
110 * par2 - Level of Looting used to kill this mob.
111 */
112 protected void dropFewItems(boolean par1, int par2)
113 {
114 if (!this.getSheared())
115 {
116 this.entityDropItem(new ItemStack(Block.cloth.blockID, 1, this.getFleeceColor()), 0.0F);
117 }
118 }
119
120 /**
121 * Returns the item ID for the item the mob drops on death.
122 */
123 protected int getDropItemId()
124 {
125 return Block.cloth.blockID;
126 }
127
128 @SideOnly(Side.CLIENT)
129 public void handleHealthUpdate(byte par1)
130 {
131 if (par1 == 10)
132 {
133 this.sheepTimer = 40;
134 }
135 else
136 {
137 super.handleHealthUpdate(par1);
138 }
139 }
140
141 /**
142 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
143 */
144 public boolean interact(EntityPlayer par1EntityPlayer)
145 {
146 return super.interact(par1EntityPlayer);
147 }
148
149 @SideOnly(Side.CLIENT)
150 public float func_70894_j(float par1)
151 {
152 return this.sheepTimer <= 0 ? 0.0F : (this.sheepTimer >= 4 && this.sheepTimer <= 36 ? 1.0F : (this.sheepTimer < 4 ? ((float)this.sheepTimer - par1) / 4.0F : -((float)(this.sheepTimer - 40) - par1) / 4.0F));
153 }
154
155 @SideOnly(Side.CLIENT)
156 public float func_70890_k(float par1)
157 {
158 if (this.sheepTimer > 4 && this.sheepTimer <= 36)
159 {
160 float var2 = ((float)(this.sheepTimer - 4) - par1) / 32.0F;
161 return ((float)Math.PI / 5F) + ((float)Math.PI * 7F / 100F) * MathHelper.sin(var2 * 28.7F);
162 }
163 else
164 {
165 return this.sheepTimer > 0 ? ((float)Math.PI / 5F) : this.rotationPitch / (180F / (float)Math.PI);
166 }
167 }
168
169 /**
170 * (abstract) Protected helper method to write subclass entity data to NBT.
171 */
172 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
173 {
174 super.writeEntityToNBT(par1NBTTagCompound);
175 par1NBTTagCompound.setBoolean("Sheared", this.getSheared());
176 par1NBTTagCompound.setByte("Color", (byte)this.getFleeceColor());
177 }
178
179 /**
180 * (abstract) Protected helper method to read subclass entity data from NBT.
181 */
182 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
183 {
184 super.readEntityFromNBT(par1NBTTagCompound);
185 this.setSheared(par1NBTTagCompound.getBoolean("Sheared"));
186 this.setFleeceColor(par1NBTTagCompound.getByte("Color"));
187 }
188
189 /**
190 * Returns the sound this mob makes while it's alive.
191 */
192 protected String getLivingSound()
193 {
194 return "mob.sheep.say";
195 }
196
197 /**
198 * Returns the sound this mob makes when it is hurt.
199 */
200 protected String getHurtSound()
201 {
202 return "mob.sheep.say";
203 }
204
205 /**
206 * Returns the sound this mob makes on death.
207 */
208 protected String getDeathSound()
209 {
210 return "mob.sheep.say";
211 }
212
213 /**
214 * Plays step sound at given x, y, z for the entity
215 */
216 protected void playStepSound(int par1, int par2, int par3, int par4)
217 {
218 this.playSound("mob.sheep.step", 0.15F, 1.0F);
219 }
220
221 public int getFleeceColor()
222 {
223 return this.dataWatcher.getWatchableObjectByte(16) & 15;
224 }
225
226 public void setFleeceColor(int par1)
227 {
228 byte var2 = this.dataWatcher.getWatchableObjectByte(16);
229 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 & 240 | par1 & 15)));
230 }
231
232 /**
233 * returns true if a sheeps wool has been sheared
234 */
235 public boolean getSheared()
236 {
237 return (this.dataWatcher.getWatchableObjectByte(16) & 16) != 0;
238 }
239
240 /**
241 * make a sheep sheared if set to true
242 */
243 public void setSheared(boolean par1)
244 {
245 byte var2 = this.dataWatcher.getWatchableObjectByte(16);
246
247 if (par1)
248 {
249 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 | 16)));
250 }
251 else
252 {
253 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 & -17)));
254 }
255 }
256
257 /**
258 * This method is called when a sheep spawns in the world to select the color of sheep fleece.
259 */
260 public static int getRandomFleeceColor(Random par0Random)
261 {
262 int var1 = par0Random.nextInt(100);
263 return var1 < 5 ? 15 : (var1 < 10 ? 7 : (var1 < 15 ? 8 : (var1 < 18 ? 12 : (par0Random.nextInt(500) == 0 ? 6 : 0))));
264 }
265
266 public EntitySheep func_90015_b(EntityAgeable par1EntityAgeable)
267 {
268 EntitySheep var2 = (EntitySheep)par1EntityAgeable;
269 EntitySheep var3 = new EntitySheep(this.worldObj);
270 int var4 = this.func_90014_a(this, var2);
271 var3.setFleeceColor(15 - var4);
272 return var3;
273 }
274
275 /**
276 * This function applies the benefits of growing back wool and faster growing up to the acting entity. (This
277 * function is used in the AIEatGrass)
278 */
279 public void eatGrassBonus()
280 {
281 this.setSheared(false);
282
283 if (this.isChild())
284 {
285 int var1 = this.getGrowingAge() + 1200;
286
287 if (var1 > 0)
288 {
289 var1 = 0;
290 }
291
292 this.setGrowingAge(var1);
293 }
294 }
295
296 /**
297 * Initialize this creature.
298 */
299 public void initCreature()
300 {
301 this.setFleeceColor(getRandomFleeceColor(this.worldObj.rand));
302 }
303
304 private int func_90014_a(EntityAnimal par1EntityAnimal, EntityAnimal par2EntityAnimal)
305 {
306 int var3 = this.func_90013_b(par1EntityAnimal);
307 int var4 = this.func_90013_b(par2EntityAnimal);
308 this.field_90016_e.getStackInSlot(0).setItemDamage(var3);
309 this.field_90016_e.getStackInSlot(1).setItemDamage(var4);
310 ItemStack var5 = CraftingManager.getInstance().findMatchingRecipe(this.field_90016_e, ((EntitySheep)par1EntityAnimal).worldObj);
311 int var6;
312
313 if (var5 != null && var5.getItem().itemID == Item.dyePowder.itemID)
314 {
315 var6 = var5.getItemDamage();
316 }
317 else
318 {
319 var6 = this.worldObj.rand.nextBoolean() ? var3 : var4;
320 }
321
322 return var6;
323 }
324
325 private int func_90013_b(EntityAnimal par1EntityAnimal)
326 {
327 return 15 - ((EntitySheep)par1EntityAnimal).getFleeceColor();
328 }
329
330 public EntityAgeable createChild(EntityAgeable par1EntityAgeable)
331 {
332 return this.func_90015_b(par1EntityAgeable);
333 }
334
335 @Override
336 public boolean isShearable(ItemStack item, World world, int X, int Y, int Z)
337 {
338 return !getSheared() && !isChild();
339 }
340
341 @Override
342 public ArrayList<ItemStack> onSheared(ItemStack item, World world, int X, int Y, int Z, int fortune)
343 {
344 ArrayList<ItemStack> ret = new ArrayList<ItemStack>();
345 setSheared(true);
346 int i = 1 + rand.nextInt(3);
347 for (int j = 0; j < i; j++)
348 {
349 ret.add(new ItemStack(Block.cloth.blockID, 1, getFleeceColor()));
350 }
351 this.worldObj.playSoundAtEntity(this, "mob.sheep.shear", 1.0F, 1.0F);
352 return ret;
353 }
354 }