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    }