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 }