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 }