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.shiftedIndex, 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
110 */
111 protected void dropFewItems(boolean par1, int par2)
112 {
113 if (!this.getSheared())
114 {
115 this.entityDropItem(new ItemStack(Block.cloth.blockID, 1, this.getFleeceColor()), 0.0F);
116 }
117 }
118
119 /**
120 * Returns the item ID for the item the mob drops on death.
121 */
122 protected int getDropItemId()
123 {
124 return Block.cloth.blockID;
125 }
126
127 @SideOnly(Side.CLIENT)
128 public void handleHealthUpdate(byte par1)
129 {
130 if (par1 == 10)
131 {
132 this.sheepTimer = 40;
133 }
134 else
135 {
136 super.handleHealthUpdate(par1);
137 }
138 }
139
140 /**
141 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
142 */
143 public boolean interact(EntityPlayer par1EntityPlayer)
144 {
145 return super.interact(par1EntityPlayer);
146 }
147
148 @SideOnly(Side.CLIENT)
149 public float func_70894_j(float par1)
150 {
151 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));
152 }
153
154 @SideOnly(Side.CLIENT)
155 public float func_70890_k(float par1)
156 {
157 if (this.sheepTimer > 4 && this.sheepTimer <= 36)
158 {
159 float var2 = ((float)(this.sheepTimer - 4) - par1) / 32.0F;
160 return ((float)Math.PI / 5F) + ((float)Math.PI * 7F / 100F) * MathHelper.sin(var2 * 28.7F);
161 }
162 else
163 {
164 return this.sheepTimer > 0 ? ((float)Math.PI / 5F) : this.rotationPitch / (180F / (float)Math.PI);
165 }
166 }
167
168 /**
169 * (abstract) Protected helper method to write subclass entity data to NBT.
170 */
171 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
172 {
173 super.writeEntityToNBT(par1NBTTagCompound);
174 par1NBTTagCompound.setBoolean("Sheared", this.getSheared());
175 par1NBTTagCompound.setByte("Color", (byte)this.getFleeceColor());
176 }
177
178 /**
179 * (abstract) Protected helper method to read subclass entity data from NBT.
180 */
181 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
182 {
183 super.readEntityFromNBT(par1NBTTagCompound);
184 this.setSheared(par1NBTTagCompound.getBoolean("Sheared"));
185 this.setFleeceColor(par1NBTTagCompound.getByte("Color"));
186 }
187
188 /**
189 * Returns the sound this mob makes while it's alive.
190 */
191 protected String getLivingSound()
192 {
193 return "mob.sheep.say";
194 }
195
196 /**
197 * Returns the sound this mob makes when it is hurt.
198 */
199 protected String getHurtSound()
200 {
201 return "mob.sheep.say";
202 }
203
204 /**
205 * Returns the sound this mob makes on death.
206 */
207 protected String getDeathSound()
208 {
209 return "mob.sheep.say";
210 }
211
212 /**
213 * Plays step sound at given x, y, z for the entity
214 */
215 protected void playStepSound(int par1, int par2, int par3, int par4)
216 {
217 this.func_85030_a("mob.sheep.step", 0.15F, 1.0F);
218 }
219
220 public int getFleeceColor()
221 {
222 return this.dataWatcher.getWatchableObjectByte(16) & 15;
223 }
224
225 public void setFleeceColor(int par1)
226 {
227 byte var2 = this.dataWatcher.getWatchableObjectByte(16);
228 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 & 240 | par1 & 15)));
229 }
230
231 /**
232 * returns true if a sheeps wool has been sheared
233 */
234 public boolean getSheared()
235 {
236 return (this.dataWatcher.getWatchableObjectByte(16) & 16) != 0;
237 }
238
239 /**
240 * make a sheep sheared if set to true
241 */
242 public void setSheared(boolean par1)
243 {
244 byte var2 = this.dataWatcher.getWatchableObjectByte(16);
245
246 if (par1)
247 {
248 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 | 16)));
249 }
250 else
251 {
252 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 & -17)));
253 }
254 }
255
256 /**
257 * This method is called when a sheep spawns in the world to select the color of sheep fleece.
258 */
259 public static int getRandomFleeceColor(Random par0Random)
260 {
261 int var1 = par0Random.nextInt(100);
262 return var1 < 5 ? 15 : (var1 < 10 ? 7 : (var1 < 15 ? 8 : (var1 < 18 ? 12 : (par0Random.nextInt(500) == 0 ? 6 : 0))));
263 }
264
265 public EntitySheep func_90015_b(EntityAgeable par1EntityAgeable)
266 {
267 EntitySheep var2 = (EntitySheep)par1EntityAgeable;
268 EntitySheep var3 = new EntitySheep(this.worldObj);
269 int var4 = this.func_90014_a(this, var2);
270 var3.setFleeceColor(15 - var4);
271 return var3;
272 }
273
274 /**
275 * This function applies the benefits of growing back wool and faster growing up to the acting entity. (This
276 * function is used in the AIEatGrass)
277 */
278 public void eatGrassBonus()
279 {
280 this.setSheared(false);
281
282 if (this.isChild())
283 {
284 int var1 = this.getGrowingAge() + 1200;
285
286 if (var1 > 0)
287 {
288 var1 = 0;
289 }
290
291 this.setGrowingAge(var1);
292 }
293 }
294
295 /**
296 * Initialize this creature.
297 */
298 public void initCreature()
299 {
300 this.setFleeceColor(getRandomFleeceColor(this.worldObj.rand));
301 }
302
303 private int func_90014_a(EntityAnimal par1EntityAnimal, EntityAnimal par2EntityAnimal)
304 {
305 int var3 = this.func_90013_b(par1EntityAnimal);
306 int var4 = this.func_90013_b(par2EntityAnimal);
307 this.field_90016_e.getStackInSlot(0).setItemDamage(var3);
308 this.field_90016_e.getStackInSlot(1).setItemDamage(var4);
309 ItemStack var5 = CraftingManager.getInstance().findMatchingRecipe(this.field_90016_e, ((EntitySheep)par1EntityAnimal).worldObj);
310 int var6;
311
312 if (var5 != null && var5.getItem().shiftedIndex == Item.dyePowder.shiftedIndex)
313 {
314 var6 = var5.getItemDamage();
315 }
316 else
317 {
318 var6 = this.worldObj.rand.nextBoolean() ? var3 : var4;
319 }
320
321 return var6;
322 }
323
324 private int func_90013_b(EntityAnimal par1EntityAnimal)
325 {
326 return 15 - ((EntitySheep)par1EntityAnimal).getFleeceColor();
327 }
328
329 public EntityAgeable func_90011_a(EntityAgeable par1EntityAgeable)
330 {
331 return this.func_90015_b(par1EntityAgeable);
332 }
333
334 @Override
335 public boolean isShearable(ItemStack item, World world, int X, int Y, int Z)
336 {
337 return !getSheared() && !isChild();
338 }
339
340 @Override
341 public ArrayList<ItemStack> onSheared(ItemStack item, World world, int X, int Y, int Z, int fortune)
342 {
343 ArrayList<ItemStack> ret = new ArrayList<ItemStack>();
344 setSheared(true);
345 int i = 1 + rand.nextInt(3);
346 for (int j = 0; j < i; j++)
347 {
348 ret.add(new ItemStack(Block.cloth.blockID, 1, getFleeceColor()));
349 }
350 this.worldObj.playSoundAtEntity(this, "mob.sheep.shear", 1.0F, 1.0F);
351 return ret;
352 }
353 }