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 }