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    }