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.Random;
007    import net.minecraft.block.material.Material;
008    import net.minecraft.creativetab.CreativeTabs;
009    import net.minecraft.entity.player.EntityPlayer;
010    import net.minecraft.item.Item;
011    import net.minecraft.item.ItemStack;
012    import net.minecraft.stats.StatList;
013    import net.minecraft.util.AxisAlignedBB;
014    import net.minecraft.util.Direction;
015    import net.minecraft.world.ColorizerFoliage;
016    import net.minecraft.world.IBlockAccess;
017    import net.minecraft.world.World;
018    
019    import net.minecraftforge.common.IShearable;
020    
021    public class BlockVine extends Block implements IShearable
022    {
023        public BlockVine(int par1)
024        {
025            super(par1, 143, Material.vine);
026            this.setTickRandomly(true);
027            this.setCreativeTab(CreativeTabs.tabDecorations);
028        }
029    
030        /**
031         * Sets the block's bounds for rendering it as an item
032         */
033        public void setBlockBoundsForItemRender()
034        {
035            this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
036        }
037    
038        /**
039         * The type of render function that is called for this block
040         */
041        public int getRenderType()
042        {
043            return 20;
044        }
045    
046        /**
047         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
048         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
049         */
050        public boolean isOpaqueCube()
051        {
052            return false;
053        }
054    
055        /**
056         * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
057         */
058        public boolean renderAsNormalBlock()
059        {
060            return false;
061        }
062    
063        /**
064         * Updates the blocks bounds based on its current state. Args: world, x, y, z
065         */
066        public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
067        {
068            int var6 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
069            float var7 = 1.0F;
070            float var8 = 1.0F;
071            float var9 = 1.0F;
072            float var10 = 0.0F;
073            float var11 = 0.0F;
074            float var12 = 0.0F;
075            boolean var13 = var6 > 0;
076    
077            if ((var6 & 2) != 0)
078            {
079                var10 = Math.max(var10, 0.0625F);
080                var7 = 0.0F;
081                var8 = 0.0F;
082                var11 = 1.0F;
083                var9 = 0.0F;
084                var12 = 1.0F;
085                var13 = true;
086            }
087    
088            if ((var6 & 8) != 0)
089            {
090                var7 = Math.min(var7, 0.9375F);
091                var10 = 1.0F;
092                var8 = 0.0F;
093                var11 = 1.0F;
094                var9 = 0.0F;
095                var12 = 1.0F;
096                var13 = true;
097            }
098    
099            if ((var6 & 4) != 0)
100            {
101                var12 = Math.max(var12, 0.0625F);
102                var9 = 0.0F;
103                var7 = 0.0F;
104                var10 = 1.0F;
105                var8 = 0.0F;
106                var11 = 1.0F;
107                var13 = true;
108            }
109    
110            if ((var6 & 1) != 0)
111            {
112                var9 = Math.min(var9, 0.9375F);
113                var12 = 1.0F;
114                var7 = 0.0F;
115                var10 = 1.0F;
116                var8 = 0.0F;
117                var11 = 1.0F;
118                var13 = true;
119            }
120    
121            if (!var13 && this.canBePlacedOn(par1IBlockAccess.getBlockId(par2, par3 + 1, par4)))
122            {
123                var8 = Math.min(var8, 0.9375F);
124                var11 = 1.0F;
125                var7 = 0.0F;
126                var10 = 1.0F;
127                var9 = 0.0F;
128                var12 = 1.0F;
129            }
130    
131            this.setBlockBounds(var7, var8, var9, var10, var11, var12);
132        }
133    
134        /**
135         * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
136         * cleared to be reused)
137         */
138        public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
139        {
140            return null;
141        }
142    
143        /**
144         * checks to see if you can place this block can be placed on that side of a block: BlockLever overrides
145         */
146        public boolean canPlaceBlockOnSide(World par1World, int par2, int par3, int par4, int par5)
147        {
148            switch (par5)
149            {
150                case 1:
151                    return this.canBePlacedOn(par1World.getBlockId(par2, par3 + 1, par4));
152                case 2:
153                    return this.canBePlacedOn(par1World.getBlockId(par2, par3, par4 + 1));
154                case 3:
155                    return this.canBePlacedOn(par1World.getBlockId(par2, par3, par4 - 1));
156                case 4:
157                    return this.canBePlacedOn(par1World.getBlockId(par2 + 1, par3, par4));
158                case 5:
159                    return this.canBePlacedOn(par1World.getBlockId(par2 - 1, par3, par4));
160                default:
161                    return false;
162            }
163        }
164    
165        /**
166         * returns true if a vine can be placed on that block (checks for render as normal block and if it is solid)
167         */
168        private boolean canBePlacedOn(int par1)
169        {
170            if (par1 == 0)
171            {
172                return false;
173            }
174            else
175            {
176                Block var2 = Block.blocksList[par1];
177                return var2.renderAsNormalBlock() && var2.blockMaterial.blocksMovement();
178            }
179        }
180    
181        /**
182         * Returns if the vine can stay in the world. It also changes the metadata according to neighboring blocks.
183         */
184        private boolean canVineStay(World par1World, int par2, int par3, int par4)
185        {
186            int var5 = par1World.getBlockMetadata(par2, par3, par4);
187            int var6 = var5;
188    
189            if (var5 > 0)
190            {
191                for (int var7 = 0; var7 <= 3; ++var7)
192                {
193                    int var8 = 1 << var7;
194    
195                    if ((var5 & var8) != 0 && !this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[var7], par3, par4 + Direction.offsetZ[var7])) && (par1World.getBlockId(par2, par3 + 1, par4) != this.blockID || (par1World.getBlockMetadata(par2, par3 + 1, par4) & var8) == 0))
196                    {
197                        var6 &= ~var8;
198                    }
199                }
200            }
201    
202            if (var6 == 0 && !this.canBePlacedOn(par1World.getBlockId(par2, par3 + 1, par4)))
203            {
204                return false;
205            }
206            else
207            {
208                if (var6 != var5)
209                {
210                    par1World.setBlockMetadataWithNotify(par2, par3, par4, var6);
211                }
212    
213                return true;
214            }
215        }
216    
217        @SideOnly(Side.CLIENT)
218        public int getBlockColor()
219        {
220            return ColorizerFoliage.getFoliageColorBasic();
221        }
222    
223        @SideOnly(Side.CLIENT)
224    
225        /**
226         * Returns the color this block should be rendered. Used by leaves.
227         */
228        public int getRenderColor(int par1)
229        {
230            return ColorizerFoliage.getFoliageColorBasic();
231        }
232    
233        @SideOnly(Side.CLIENT)
234    
235        /**
236         * Returns a integer with hex for 0xrrggbb with this color multiplied against the blocks color. Note only called
237         * when first determining what to render.
238         */
239        public int colorMultiplier(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
240        {
241            return par1IBlockAccess.getBiomeGenForCoords(par2, par4).getBiomeFoliageColor();
242        }
243    
244        /**
245         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
246         * their own) Args: x, y, z, neighbor blockID
247         */
248        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
249        {
250            if (!par1World.isRemote && !this.canVineStay(par1World, par2, par3, par4))
251            {
252                this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
253                par1World.setBlockWithNotify(par2, par3, par4, 0);
254            }
255        }
256    
257        /**
258         * Ticks the block if it's been scheduled
259         */
260        public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
261        {
262            if (!par1World.isRemote && par1World.rand.nextInt(4) == 0)
263            {
264                byte var6 = 4;
265                int var7 = 5;
266                boolean var8 = false;
267                int var9;
268                int var10;
269                int var11;
270                label138:
271    
272                for (var9 = par2 - var6; var9 <= par2 + var6; ++var9)
273                {
274                    for (var10 = par4 - var6; var10 <= par4 + var6; ++var10)
275                    {
276                        for (var11 = par3 - 1; var11 <= par3 + 1; ++var11)
277                        {
278                            if (par1World.getBlockId(var9, var11, var10) == this.blockID)
279                            {
280                                --var7;
281    
282                                if (var7 <= 0)
283                                {
284                                    var8 = true;
285                                    break label138;
286                                }
287                            }
288                        }
289                    }
290                }
291    
292                var9 = par1World.getBlockMetadata(par2, par3, par4);
293                var10 = par1World.rand.nextInt(6);
294                var11 = Direction.vineGrowth[var10];
295                int var12;
296                int var13;
297    
298                if (var10 == 1 && par3 < 255 && par1World.isAirBlock(par2, par3 + 1, par4))
299                {
300                    if (var8)
301                    {
302                        return;
303                    }
304    
305                    var12 = par1World.rand.nextInt(16) & var9;
306    
307                    if (var12 > 0)
308                    {
309                        for (var13 = 0; var13 <= 3; ++var13)
310                        {
311                            if (!this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[var13], par3 + 1, par4 + Direction.offsetZ[var13])))
312                            {
313                                var12 &= ~(1 << var13);
314                            }
315                        }
316    
317                        if (var12 > 0)
318                        {
319                            par1World.setBlockAndMetadataWithNotify(par2, par3 + 1, par4, this.blockID, var12);
320                        }
321                    }
322                }
323                else
324                {
325                    int var14;
326    
327                    if (var10 >= 2 && var10 <= 5 && (var9 & 1 << var11) == 0)
328                    {
329                        if (var8)
330                        {
331                            return;
332                        }
333    
334                        var12 = par1World.getBlockId(par2 + Direction.offsetX[var11], par3, par4 + Direction.offsetZ[var11]);
335    
336                        if (var12 != 0 && Block.blocksList[var12] != null)
337                        {
338                            if (Block.blocksList[var12].blockMaterial.isOpaque() && Block.blocksList[var12].renderAsNormalBlock())
339                            {
340                                par1World.setBlockMetadataWithNotify(par2, par3, par4, var9 | 1 << var11);
341                            }
342                        }
343                        else
344                        {
345                            var13 = var11 + 1 & 3;
346                            var14 = var11 + 3 & 3;
347    
348                            if ((var9 & 1 << var13) != 0 && this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[var11] + Direction.offsetX[var13], par3, par4 + Direction.offsetZ[var11] + Direction.offsetZ[var13])))
349                            {
350                                par1World.setBlockAndMetadataWithNotify(par2 + Direction.offsetX[var11], par3, par4 + Direction.offsetZ[var11], this.blockID, 1 << var13);
351                            }
352                            else if ((var9 & 1 << var14) != 0 && this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[var11] + Direction.offsetX[var14], par3, par4 + Direction.offsetZ[var11] + Direction.offsetZ[var14])))
353                            {
354                                par1World.setBlockAndMetadataWithNotify(par2 + Direction.offsetX[var11], par3, par4 + Direction.offsetZ[var11], this.blockID, 1 << var14);
355                            }
356                            else if ((var9 & 1 << var13) != 0 && par1World.isAirBlock(par2 + Direction.offsetX[var11] + Direction.offsetX[var13], par3, par4 + Direction.offsetZ[var11] + Direction.offsetZ[var13]) && this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[var13], par3, par4 + Direction.offsetZ[var13])))
357                            {
358                                par1World.setBlockAndMetadataWithNotify(par2 + Direction.offsetX[var11] + Direction.offsetX[var13], par3, par4 + Direction.offsetZ[var11] + Direction.offsetZ[var13], this.blockID, 1 << (var11 + 2 & 3));
359                            }
360                            else if ((var9 & 1 << var14) != 0 && par1World.isAirBlock(par2 + Direction.offsetX[var11] + Direction.offsetX[var14], par3, par4 + Direction.offsetZ[var11] + Direction.offsetZ[var14]) && this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[var14], par3, par4 + Direction.offsetZ[var14])))
361                            {
362                                par1World.setBlockAndMetadataWithNotify(par2 + Direction.offsetX[var11] + Direction.offsetX[var14], par3, par4 + Direction.offsetZ[var11] + Direction.offsetZ[var14], this.blockID, 1 << (var11 + 2 & 3));
363                            }
364                            else if (this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[var11], par3 + 1, par4 + Direction.offsetZ[var11])))
365                            {
366                                par1World.setBlockAndMetadataWithNotify(par2 + Direction.offsetX[var11], par3, par4 + Direction.offsetZ[var11], this.blockID, 0);
367                            }
368                        }
369                    }
370                    else if (par3 > 1)
371                    {
372                        var12 = par1World.getBlockId(par2, par3 - 1, par4);
373    
374                        if (var12 == 0)
375                        {
376                            var13 = par1World.rand.nextInt(16) & var9;
377    
378                            if (var13 > 0)
379                            {
380                                par1World.setBlockAndMetadataWithNotify(par2, par3 - 1, par4, this.blockID, var13);
381                            }
382                        }
383                        else if (var12 == this.blockID)
384                        {
385                            var13 = par1World.rand.nextInt(16) & var9;
386                            var14 = par1World.getBlockMetadata(par2, par3 - 1, par4);
387    
388                            if (var14 != (var14 | var13))
389                            {
390                                par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, var14 | var13);
391                            }
392                        }
393                    }
394                }
395            }
396        }
397    
398        public int func_85104_a(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9)
399        {
400            byte var10 = 0;
401    
402            switch (par5)
403            {
404                case 2:
405                    var10 = 1;
406                    break;
407                case 3:
408                    var10 = 4;
409                    break;
410                case 4:
411                    var10 = 8;
412                    break;
413                case 5:
414                    var10 = 2;
415            }
416    
417            return var10 != 0 ? var10 : par9;
418        }
419    
420        /**
421         * Returns the ID of the items to drop on destruction.
422         */
423        public int idDropped(int par1, Random par2Random, int par3)
424        {
425            return 0;
426        }
427    
428        /**
429         * Returns the quantity of items to drop on block destruction.
430         */
431        public int quantityDropped(Random par1Random)
432        {
433            return 0;
434        }
435    
436        /**
437         * Called when the player destroys a block with an item that can harvest it. (i, j, k) are the coordinates of the
438         * block and l is the block's subtype/damage.
439         */
440        public void harvestBlock(World par1World, EntityPlayer par2EntityPlayer, int par3, int par4, int par5, int par6)
441        {
442            super.harvestBlock(par1World, par2EntityPlayer, par3, par4, par5, par6);
443        }
444        
445        @Override
446        public boolean isShearable(ItemStack item, World world, int x, int y, int z) 
447        {
448            return true;
449        }
450        
451        @Override
452        public ArrayList<ItemStack> onSheared(ItemStack item, World world, int x, int y, int z, int fortune) 
453        {
454            ArrayList<ItemStack> ret = new ArrayList<ItemStack>();
455            ret.add(new ItemStack(this, 1, 0));
456            return ret;
457        }
458        
459        @Override
460        public boolean isLadder(World world, int x, int y, int z) 
461        {
462            return true;
463        }
464    }