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