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 }