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, 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 l = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
070        float f = 1.0F;
071        float f1 = 1.0F;
072        float f2 = 1.0F;
073        float f3 = 0.0F;
074        float f4 = 0.0F;
075        float f5 = 0.0F;
076        boolean flag = l > 0;
077
078        if ((l & 2) != 0)
079        {
080            f3 = Math.max(f3, 0.0625F);
081            f = 0.0F;
082            f1 = 0.0F;
083            f4 = 1.0F;
084            f2 = 0.0F;
085            f5 = 1.0F;
086            flag = true;
087        }
088
089        if ((l & 8) != 0)
090        {
091            f = Math.min(f, 0.9375F);
092            f3 = 1.0F;
093            f1 = 0.0F;
094            f4 = 1.0F;
095            f2 = 0.0F;
096            f5 = 1.0F;
097            flag = true;
098        }
099
100        if ((l & 4) != 0)
101        {
102            f5 = Math.max(f5, 0.0625F);
103            f2 = 0.0F;
104            f = 0.0F;
105            f3 = 1.0F;
106            f1 = 0.0F;
107            f4 = 1.0F;
108            flag = true;
109        }
110
111        if ((l & 1) != 0)
112        {
113            f2 = Math.min(f2, 0.9375F);
114            f5 = 1.0F;
115            f = 0.0F;
116            f3 = 1.0F;
117            f1 = 0.0F;
118            f4 = 1.0F;
119            flag = true;
120        }
121
122        if (!flag && this.canBePlacedOn(par1IBlockAccess.getBlockId(par2, par3 + 1, par4)))
123        {
124            f1 = Math.min(f1, 0.9375F);
125            f4 = 1.0F;
126            f = 0.0F;
127            f3 = 1.0F;
128            f2 = 0.0F;
129            f5 = 1.0F;
130        }
131
132        this.setBlockBounds(f, f1, f2, f3, f4, f5);
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 block = Block.blocksList[par1];
178            return block.renderAsNormalBlock() && block.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 l = par1World.getBlockMetadata(par2, par3, par4);
188        int i1 = l;
189
190        if (l > 0)
191        {
192            for (int j1 = 0; j1 <= 3; ++j1)
193            {
194                int k1 = 1 << j1;
195
196                if ((l & k1) != 0 && !this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[j1], par3, par4 + Direction.offsetZ[j1])) && (par1World.getBlockId(par2, par3 + 1, par4) != this.blockID || (par1World.getBlockMetadata(par2, par3 + 1, par4) & k1) == 0))
197                {
198                    i1 &= ~k1;
199                }
200            }
201        }
202
203        if (i1 == 0 && !this.canBePlacedOn(par1World.getBlockId(par2, par3 + 1, par4)))
204        {
205            return false;
206        }
207        else
208        {
209            if (i1 != l)
210            {
211                par1World.setBlockMetadataWithNotify(par2, par3, par4, i1, 2);
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.setBlockToAir(par2, par3, par4);
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 b0 = 4;
266            int l = 5;
267            boolean flag = false;
268            int i1;
269            int j1;
270            int k1;
271            label138:
272
273            for (i1 = par2 - b0; i1 <= par2 + b0; ++i1)
274            {
275                for (j1 = par4 - b0; j1 <= par4 + b0; ++j1)
276                {
277                    for (k1 = par3 - 1; k1 <= par3 + 1; ++k1)
278                    {
279                        if (par1World.getBlockId(i1, k1, j1) == this.blockID)
280                        {
281                            --l;
282
283                            if (l <= 0)
284                            {
285                                flag = true;
286                                break label138;
287                            }
288                        }
289                    }
290                }
291            }
292
293            i1 = par1World.getBlockMetadata(par2, par3, par4);
294            j1 = par1World.rand.nextInt(6);
295            k1 = Direction.facingToDirection[j1];
296            int l1;
297            int i2;
298
299            if (j1 == 1 && par3 < 255 && par1World.isAirBlock(par2, par3 + 1, par4))
300            {
301                if (flag)
302                {
303                    return;
304                }
305
306                l1 = par1World.rand.nextInt(16) & i1;
307
308                if (l1 > 0)
309                {
310                    for (i2 = 0; i2 <= 3; ++i2)
311                    {
312                        if (!this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[i2], par3 + 1, par4 + Direction.offsetZ[i2])))
313                        {
314                            l1 &= ~(1 << i2);
315                        }
316                    }
317
318                    if (l1 > 0)
319                    {
320                        par1World.setBlock(par2, par3 + 1, par4, this.blockID, l1, 2);
321                    }
322                }
323            }
324            else
325            {
326                int j2;
327
328                if (j1 >= 2 && j1 <= 5 && (i1 & 1 << k1) == 0)
329                {
330                    if (flag)
331                    {
332                        return;
333                    }
334
335                    l1 = par1World.getBlockId(par2 + Direction.offsetX[k1], par3, par4 + Direction.offsetZ[k1]);
336
337                    if (l1 != 0 && Block.blocksList[l1] != null)
338                    {
339                        if (Block.blocksList[l1].blockMaterial.isOpaque() && Block.blocksList[l1].renderAsNormalBlock())
340                        {
341                            par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 | 1 << k1, 2);
342                        }
343                    }
344                    else
345                    {
346                        i2 = k1 + 1 & 3;
347                        j2 = k1 + 3 & 3;
348
349                        if ((i1 & 1 << i2) != 0 && this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[k1] + Direction.offsetX[i2], par3, par4 + Direction.offsetZ[k1] + Direction.offsetZ[i2])))
350                        {
351                            par1World.setBlock(par2 + Direction.offsetX[k1], par3, par4 + Direction.offsetZ[k1], this.blockID, 1 << i2, 2);
352                        }
353                        else if ((i1 & 1 << j2) != 0 && this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[k1] + Direction.offsetX[j2], par3, par4 + Direction.offsetZ[k1] + Direction.offsetZ[j2])))
354                        {
355                            par1World.setBlock(par2 + Direction.offsetX[k1], par3, par4 + Direction.offsetZ[k1], this.blockID, 1 << j2, 2);
356                        }
357                        else if ((i1 & 1 << i2) != 0 && par1World.isAirBlock(par2 + Direction.offsetX[k1] + Direction.offsetX[i2], par3, par4 + Direction.offsetZ[k1] + Direction.offsetZ[i2]) && this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[i2], par3, par4 + Direction.offsetZ[i2])))
358                        {
359                            par1World.setBlock(par2 + Direction.offsetX[k1] + Direction.offsetX[i2], par3, par4 + Direction.offsetZ[k1] + Direction.offsetZ[i2], this.blockID, 1 << (k1 + 2 & 3), 2);
360                        }
361                        else if ((i1 & 1 << j2) != 0 && par1World.isAirBlock(par2 + Direction.offsetX[k1] + Direction.offsetX[j2], par3, par4 + Direction.offsetZ[k1] + Direction.offsetZ[j2]) && this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[j2], par3, par4 + Direction.offsetZ[j2])))
362                        {
363                            par1World.setBlock(par2 + Direction.offsetX[k1] + Direction.offsetX[j2], par3, par4 + Direction.offsetZ[k1] + Direction.offsetZ[j2], this.blockID, 1 << (k1 + 2 & 3), 2);
364                        }
365                        else if (this.canBePlacedOn(par1World.getBlockId(par2 + Direction.offsetX[k1], par3 + 1, par4 + Direction.offsetZ[k1])))
366                        {
367                            par1World.setBlock(par2 + Direction.offsetX[k1], par3, par4 + Direction.offsetZ[k1], this.blockID, 0, 2);
368                        }
369                    }
370                }
371                else if (par3 > 1)
372                {
373                    l1 = par1World.getBlockId(par2, par3 - 1, par4);
374
375                    if (l1 == 0)
376                    {
377                        i2 = par1World.rand.nextInt(16) & i1;
378
379                        if (i2 > 0)
380                        {
381                            par1World.setBlock(par2, par3 - 1, par4, this.blockID, i2, 2);
382                        }
383                    }
384                    else if (l1 == this.blockID)
385                    {
386                        i2 = par1World.rand.nextInt(16) & i1;
387                        j2 = par1World.getBlockMetadata(par2, par3 - 1, par4);
388
389                        if (j2 != (j2 | i2))
390                        {
391                            par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, j2 | i2, 2);
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 b0 = 0;
405
406        switch (par5)
407        {
408            case 2:
409                b0 = 1;
410                break;
411            case 3:
412                b0 = 4;
413                break;
414            case 4:
415                b0 = 8;
416                break;
417            case 5:
418                b0 = 2;
419        }
420
421        return b0 != 0 ? b0 : 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}