    001package net.minecraft.entity.passive;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005
    006import java.util.ArrayList;
    007import java.util.Random;
    008import net.minecraft.block.Block;
    009import net.minecraft.entity.EntityAgeable;
    010import net.minecraft.entity.ai.EntityAIEatGrass;
    011import net.minecraft.entity.ai.EntityAIFollowParent;
    012import net.minecraft.entity.ai.EntityAILookIdle;
    013import net.minecraft.entity.ai.EntityAIMate;
    014import net.minecraft.entity.ai.EntityAIPanic;
    015import net.minecraft.entity.ai.EntityAISwimming;
    016import net.minecraft.entity.ai.EntityAITempt;
    017import net.minecraft.entity.ai.EntityAIWander;
    018import net.minecraft.entity.ai.EntityAIWatchClosest;
    019import net.minecraft.entity.item.EntityItem;
    020import net.minecraft.entity.player.EntityPlayer;
    021import net.minecraft.inventory.InventoryCrafting;
    022import net.minecraft.item.Item;
    023import net.minecraft.item.ItemStack;
    024import net.minecraft.item.crafting.CraftingManager;
    025import net.minecraft.nbt.NBTTagCompound;
    026import net.minecraft.util.MathHelper;
    027import net.minecraft.world.World;
    028
    029import net.minecraftforge.common.IShearable;
    030
    031public 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}