001package net.minecraft.block;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005
006import java.util.ArrayList;
007import java.util.Random;
008import net.minecraft.block.material.Material;
009import net.minecraft.creativetab.CreativeTabs;
010import net.minecraft.entity.player.EntityPlayer;
011import net.minecraft.item.Item;
012import net.minecraft.item.ItemStack;
013import net.minecraft.stats.StatList;
014import net.minecraft.util.AxisAlignedBB;
015import net.minecraft.util.Direction;
016import net.minecraft.world.ColorizerFoliage;
017import net.minecraft.world.IBlockAccess;
018import net.minecraft.world.World;
019
020import net.minecraftforge.common.IShearable;
021
022public 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}