001 package net.minecraft.block;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.SideOnly;
005 import java.util.ArrayList;
006 import java.util.List;
007 import java.util.Random;
008 import net.minecraft.block.material.Material;
009 import net.minecraft.creativetab.CreativeTabs;
010 import net.minecraft.entity.player.EntityPlayer;
011 import net.minecraft.item.Item;
012 import net.minecraft.item.ItemStack;
013 import net.minecraft.stats.StatList;
014 import net.minecraft.world.ColorizerFoliage;
015 import net.minecraft.world.IBlockAccess;
016 import net.minecraft.world.World;
017
018 import net.minecraftforge.common.IShearable;
019
020 public class BlockLeaves extends BlockLeavesBase implements IShearable
021 {
022 /**
023 * The base index in terrain.png corresponding to the fancy version of the leaf texture. This is stored so we can
024 * switch the displayed version between fancy and fast graphics (fast is this index + 1).
025 */
026 private int baseIndexInPNG;
027 public static final String[] LEAF_TYPES = new String[] {"oak", "spruce", "birch", "jungle"};
028 int[] adjacentTreeBlocks;
029
030 protected BlockLeaves(int par1, int par2)
031 {
032 super(par1, par2, Material.leaves, false);
033 this.baseIndexInPNG = par2;
034 this.setTickRandomly(true);
035 this.setCreativeTab(CreativeTabs.tabDecorations);
036 }
037
038 @SideOnly(Side.CLIENT)
039 public int getBlockColor()
040 {
041 double var1 = 0.5D;
042 double var3 = 1.0D;
043 return ColorizerFoliage.getFoliageColor(var1, var3);
044 }
045
046 @SideOnly(Side.CLIENT)
047
048 /**
049 * Returns the color this block should be rendered. Used by leaves.
050 */
051 public int getRenderColor(int par1)
052 {
053 return (par1 & 3) == 1 ? ColorizerFoliage.getFoliageColorPine() : ((par1 & 3) == 2 ? ColorizerFoliage.getFoliageColorBirch() : ColorizerFoliage.getFoliageColorBasic());
054 }
055
056 @SideOnly(Side.CLIENT)
057
058 /**
059 * Returns a integer with hex for 0xrrggbb with this color multiplied against the blocks color. Note only called
060 * when first determining what to render.
061 */
062 public int colorMultiplier(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
063 {
064 int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
065
066 if ((var5 & 3) == 1)
067 {
068 return ColorizerFoliage.getFoliageColorPine();
069 }
070 else if ((var5 & 3) == 2)
071 {
072 return ColorizerFoliage.getFoliageColorBirch();
073 }
074 else
075 {
076 int var6 = 0;
077 int var7 = 0;
078 int var8 = 0;
079
080 for (int var9 = -1; var9 <= 1; ++var9)
081 {
082 for (int var10 = -1; var10 <= 1; ++var10)
083 {
084 int var11 = par1IBlockAccess.getBiomeGenForCoords(par2 + var10, par4 + var9).getBiomeFoliageColor();
085 var6 += (var11 & 16711680) >> 16;
086 var7 += (var11 & 65280) >> 8;
087 var8 += var11 & 255;
088 }
089 }
090
091 return (var6 / 9 & 255) << 16 | (var7 / 9 & 255) << 8 | var8 / 9 & 255;
092 }
093 }
094
095 /**
096 * ejects contained items into the world, and notifies neighbours of an update, as appropriate
097 */
098 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
099 {
100 byte var7 = 1;
101 int var8 = var7 + 1;
102
103 if (par1World.checkChunksExist(par2 - var8, par3 - var8, par4 - var8, par2 + var8, par3 + var8, par4 + var8))
104 {
105 for (int var9 = -var7; var9 <= var7; ++var9)
106 {
107 for (int var10 = -var7; var10 <= var7; ++var10)
108 {
109 for (int var11 = -var7; var11 <= var7; ++var11)
110 {
111 int var12 = par1World.getBlockId(par2 + var9, par3 + var10, par4 + var11);
112
113 if (Block.blocksList[var12] != null)
114 {
115 Block.blocksList[var12].beginLeavesDecay(par1World, par2 + var9, par3 + var10, par4 + var11);
116 }
117 }
118 }
119 }
120 }
121 }
122
123 /**
124 * Ticks the block if it's been scheduled
125 */
126 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
127 {
128 if (!par1World.isRemote)
129 {
130 int var6 = par1World.getBlockMetadata(par2, par3, par4);
131
132 if ((var6 & 8) != 0 && (var6 & 4) == 0)
133 {
134 byte var7 = 4;
135 int var8 = var7 + 1;
136 byte var9 = 32;
137 int var10 = var9 * var9;
138 int var11 = var9 / 2;
139
140 if (this.adjacentTreeBlocks == null)
141 {
142 this.adjacentTreeBlocks = new int[var9 * var9 * var9];
143 }
144
145 int var12;
146
147 if (par1World.checkChunksExist(par2 - var8, par3 - var8, par4 - var8, par2 + var8, par3 + var8, par4 + var8))
148 {
149 int var13;
150 int var14;
151 int var15;
152
153 for (var12 = -var7; var12 <= var7; ++var12)
154 {
155 for (var13 = -var7; var13 <= var7; ++var13)
156 {
157 for (var14 = -var7; var14 <= var7; ++var14)
158 {
159 var15 = par1World.getBlockId(par2 + var12, par3 + var13, par4 + var14);
160
161 Block block = Block.blocksList[var15];
162
163 if (block != null && block.canSustainLeaves(par1World, par2 + var12, par3 + var13, par4 + var14))
164 {
165 this.adjacentTreeBlocks[(var12 + var11) * var10 + (var13 + var11) * var9 + var14 + var11] = 0;
166 }
167 else if (block != null && block.isLeaves(par1World, par2 + var12, par3 + var13, par4 + var14))
168 {
169 this.adjacentTreeBlocks[(var12 + var11) * var10 + (var13 + var11) * var9 + var14 + var11] = -2;
170 }
171 else
172 {
173 this.adjacentTreeBlocks[(var12 + var11) * var10 + (var13 + var11) * var9 + var14 + var11] = -1;
174 }
175 }
176 }
177 }
178
179 for (var12 = 1; var12 <= 4; ++var12)
180 {
181 for (var13 = -var7; var13 <= var7; ++var13)
182 {
183 for (var14 = -var7; var14 <= var7; ++var14)
184 {
185 for (var15 = -var7; var15 <= var7; ++var15)
186 {
187 if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + var15 + var11] == var12 - 1)
188 {
189 if (this.adjacentTreeBlocks[(var13 + var11 - 1) * var10 + (var14 + var11) * var9 + var15 + var11] == -2)
190 {
191 this.adjacentTreeBlocks[(var13 + var11 - 1) * var10 + (var14 + var11) * var9 + var15 + var11] = var12;
192 }
193
194 if (this.adjacentTreeBlocks[(var13 + var11 + 1) * var10 + (var14 + var11) * var9 + var15 + var11] == -2)
195 {
196 this.adjacentTreeBlocks[(var13 + var11 + 1) * var10 + (var14 + var11) * var9 + var15 + var11] = var12;
197 }
198
199 if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11 - 1) * var9 + var15 + var11] == -2)
200 {
201 this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11 - 1) * var9 + var15 + var11] = var12;
202 }
203
204 if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11 + 1) * var9 + var15 + var11] == -2)
205 {
206 this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11 + 1) * var9 + var15 + var11] = var12;
207 }
208
209 if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + (var15 + var11 - 1)] == -2)
210 {
211 this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + (var15 + var11 - 1)] = var12;
212 }
213
214 if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + var15 + var11 + 1] == -2)
215 {
216 this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + var15 + var11 + 1] = var12;
217 }
218 }
219 }
220 }
221 }
222 }
223 }
224
225 var12 = this.adjacentTreeBlocks[var11 * var10 + var11 * var9 + var11];
226
227 if (var12 >= 0)
228 {
229 par1World.setBlockMetadata(par2, par3, par4, var6 & -9);
230 }
231 else
232 {
233 this.removeLeaves(par1World, par2, par3, par4);
234 }
235 }
236 }
237 }
238
239 @SideOnly(Side.CLIENT)
240
241 /**
242 * A randomly called display update to be able to add particles or other items for display
243 */
244 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
245 {
246 if (par1World.canLightningStrikeAt(par2, par3 + 1, par4) && !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && par5Random.nextInt(15) == 1)
247 {
248 double var6 = (double)((float)par2 + par5Random.nextFloat());
249 double var8 = (double)par3 - 0.05D;
250 double var10 = (double)((float)par4 + par5Random.nextFloat());
251 par1World.spawnParticle("dripWater", var6, var8, var10, 0.0D, 0.0D, 0.0D);
252 }
253 }
254
255 private void removeLeaves(World par1World, int par2, int par3, int par4)
256 {
257 this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
258 par1World.setBlockWithNotify(par2, par3, par4, 0);
259 }
260
261 /**
262 * Returns the quantity of items to drop on block destruction.
263 */
264 public int quantityDropped(Random par1Random)
265 {
266 return par1Random.nextInt(20) == 0 ? 1 : 0;
267 }
268
269 /**
270 * Returns the ID of the items to drop on destruction.
271 */
272 public int idDropped(int par1, Random par2Random, int par3)
273 {
274 return Block.sapling.blockID;
275 }
276
277 /**
278 * Drops the block items with a specified chance of dropping the specified items
279 */
280 public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7)
281 {
282 if (!par1World.isRemote)
283 {
284 byte var8 = 20;
285
286 if ((par5 & 3) == 3)
287 {
288 var8 = 40;
289 }
290
291 if (par1World.rand.nextInt(var8) == 0)
292 {
293 int var9 = this.idDropped(par5, par1World.rand, par7);
294 this.dropBlockAsItem_do(par1World, par2, par3, par4, new ItemStack(var9, 1, this.damageDropped(par5)));
295 }
296
297 if ((par5 & 3) == 0 && par1World.rand.nextInt(200) == 0)
298 {
299 this.dropBlockAsItem_do(par1World, par2, par3, par4, new ItemStack(Item.appleRed, 1, 0));
300 }
301 }
302 }
303
304 /**
305 * Called when the player destroys a block with an item that can harvest it. (i, j, k) are the coordinates of the
306 * block and l is the block's subtype/damage.
307 */
308 public void harvestBlock(World par1World, EntityPlayer par2EntityPlayer, int par3, int par4, int par5, int par6)
309 {
310 super.harvestBlock(par1World, par2EntityPlayer, par3, par4, par5, par6);
311 }
312
313 /**
314 * Determines the damage on the item the block drops. Used in cloth and wood.
315 */
316 public int damageDropped(int par1)
317 {
318 return par1 & 3;
319 }
320
321 /**
322 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
323 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
324 */
325 public boolean isOpaqueCube()
326 {
327 return !this.graphicsLevel;
328 }
329
330 /**
331 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
332 */
333 public int getBlockTextureFromSideAndMetadata(int par1, int par2)
334 {
335 return (par2 & 3) == 1 ? this.blockIndexInTexture + 80 : ((par2 & 3) == 3 ? this.blockIndexInTexture + 144 : this.blockIndexInTexture);
336 }
337
338 @SideOnly(Side.CLIENT)
339
340 /**
341 * Pass true to draw this block using fancy graphics, or false for fast graphics.
342 */
343 public void setGraphicsLevel(boolean par1)
344 {
345 this.graphicsLevel = par1;
346 this.blockIndexInTexture = this.baseIndexInPNG + (par1 ? 0 : 1);
347 }
348
349 @SideOnly(Side.CLIENT)
350
351 /**
352 * returns a list of blocks with the same ID, but different meta (eg: wood returns 4 blocks)
353 */
354 public void getSubBlocks(int par1, CreativeTabs par2CreativeTabs, List par3List)
355 {
356 par3List.add(new ItemStack(par1, 1, 0));
357 par3List.add(new ItemStack(par1, 1, 1));
358 par3List.add(new ItemStack(par1, 1, 2));
359 par3List.add(new ItemStack(par1, 1, 3));
360 }
361
362 @Override
363 public boolean isShearable(ItemStack item, World world, int x, int y, int z)
364 {
365 return true;
366 }
367
368 @Override
369 public ArrayList<ItemStack> onSheared(ItemStack item, World world, int x, int y, int z, int fortune)
370 {
371 ArrayList<ItemStack> ret = new ArrayList<ItemStack>();
372 ret.add(new ItemStack(this, 1, world.getBlockMetadata(x, y, z) & 3));
373 return ret;
374 }
375
376 @Override
377 public void beginLeavesDecay(World world, int x, int y, int z)
378 {
379 world.setBlockMetadata(x, y, z, world.getBlockMetadata(x, y, z) | 8);
380 }
381
382 @Override
383 public boolean isLeaves(World world, int x, int y, int z)
384 {
385 return true;
386 }
387 }