001 package net.minecraft.src; 002 003 import cpw.mods.fml.common.Side; 004 import cpw.mods.fml.common.asm.SideOnly; 005 import java.util.List; 006 007 public class BlockPistonBase extends Block 008 { 009 /** This pistons is the sticky one? */ 010 private boolean isSticky; 011 012 public BlockPistonBase(int par1, int par2, boolean par3) 013 { 014 super(par1, par2, Material.piston); 015 this.isSticky = par3; 016 this.setStepSound(soundStoneFootstep); 017 this.setHardness(0.5F); 018 this.setCreativeTab(CreativeTabs.tabRedstone); 019 } 020 021 @SideOnly(Side.CLIENT) 022 023 /** 024 * Return the either 106 or 107 as the texture index depending on the isSticky flag. This will actually never get 025 * called by TileEntityRendererPiston.renderPiston() because TileEntityPiston.shouldRenderHead() will always return 026 * false. 027 */ 028 public int getPistonExtensionTexture() 029 { 030 return this.isSticky ? 106 : 107; 031 } 032 033 /** 034 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 035 */ 036 public int getBlockTextureFromSideAndMetadata(int par1, int par2) 037 { 038 int var3 = getOrientation(par2); 039 return var3 > 5 ? this.blockIndexInTexture : (par1 == var3 ? (!isExtended(par2) && this.minX <= 0.0D && this.minY <= 0.0D && this.minZ <= 0.0D && this.maxX >= 1.0D && this.maxY >= 1.0D && this.maxZ >= 1.0D ? this.blockIndexInTexture : 110) : (par1 == Facing.faceToSide[var3] ? 109 : 108)); 040 } 041 042 /** 043 * The type of render function that is called for this block 044 */ 045 public int getRenderType() 046 { 047 return 16; 048 } 049 050 /** 051 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 052 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 053 */ 054 public boolean isOpaqueCube() 055 { 056 return false; 057 } 058 059 /** 060 * Called upon block activation (right click on the block.) 061 */ 062 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 063 { 064 return false; 065 } 066 067 /** 068 * Called when the block is placed in the world. 069 */ 070 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving) 071 { 072 int var6 = determineOrientation(par1World, par2, par3, par4, (EntityPlayer)par5EntityLiving); 073 par1World.setBlockMetadataWithNotify(par2, par3, par4, var6); 074 075 if (!par1World.isRemote) 076 { 077 this.updatePistonState(par1World, par2, par3, par4); 078 } 079 } 080 081 /** 082 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 083 * their own) Args: x, y, z, neighbor blockID 084 */ 085 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 086 { 087 if (!par1World.isRemote) 088 { 089 this.updatePistonState(par1World, par2, par3, par4); 090 } 091 } 092 093 /** 094 * Called whenever the block is added into the world. Args: world, x, y, z 095 */ 096 public void onBlockAdded(World par1World, int par2, int par3, int par4) 097 { 098 if (!par1World.isRemote && par1World.getBlockTileEntity(par2, par3, par4) == null) 099 { 100 this.updatePistonState(par1World, par2, par3, par4); 101 } 102 } 103 104 /** 105 * handles attempts to extend or retract the piston. 106 */ 107 private void updatePistonState(World par1World, int par2, int par3, int par4) 108 { 109 int var5 = par1World.getBlockMetadata(par2, par3, par4); 110 int var6 = getOrientation(var5); 111 112 if (var6 != 7) 113 { 114 boolean var7 = this.isIndirectlyPowered(par1World, par2, par3, par4, var6); 115 116 if (var7 && !isExtended(var5)) 117 { 118 if (canExtend(par1World, par2, par3, par4, var6)) 119 { 120 par1World.addBlockEvent(par2, par3, par4, this.blockID, 0, var6); 121 } 122 } 123 else if (!var7 && isExtended(var5)) 124 { 125 par1World.addBlockEvent(par2, par3, par4, this.blockID, 1, var6); 126 } 127 } 128 } 129 130 /** 131 * checks the block to that side to see if it is indirectly powered. 132 */ 133 private boolean isIndirectlyPowered(World par1World, int par2, int par3, int par4, int par5) 134 { 135 return par5 != 0 && par1World.isBlockIndirectlyProvidingPowerTo(par2, par3 - 1, par4, 0) ? true : (par5 != 1 && par1World.isBlockIndirectlyProvidingPowerTo(par2, par3 + 1, par4, 1) ? true : (par5 != 2 && par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 - 1, 2) ? true : (par5 != 3 && par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 + 1, 3) ? true : (par5 != 5 && par1World.isBlockIndirectlyProvidingPowerTo(par2 + 1, par3, par4, 5) ? true : (par5 != 4 && par1World.isBlockIndirectlyProvidingPowerTo(par2 - 1, par3, par4, 4) ? true : (par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4, 0) ? true : (par1World.isBlockIndirectlyProvidingPowerTo(par2, par3 + 2, par4, 1) ? true : (par1World.isBlockIndirectlyProvidingPowerTo(par2, par3 + 1, par4 - 1, 2) ? true : (par1World.isBlockIndirectlyProvidingPowerTo(par2, par3 + 1, par4 + 1, 3) ? true : (par1World.isBlockIndirectlyProvidingPowerTo(par2 - 1, par3 + 1, par4, 4) ? true : par1World.isBlockIndirectlyProvidingPowerTo(par2 + 1, par3 + 1, par4, 5))))))))))); 136 } 137 138 /** 139 * Called when the block receives a BlockEvent - see World.addBlockEvent. By default, passes it on to the tile 140 * entity at this location. Args: world, x, y, z, blockID, EventID, event parameter 141 */ 142 public void onBlockEventReceived(World par1World, int par2, int par3, int par4, int par5, int par6) 143 { 144 if (par5 == 0) 145 { 146 par1World.setBlockMetadata(par2, par3, par4, par6 | 8); 147 } 148 else 149 { 150 par1World.setBlockMetadata(par2, par3, par4, par6); 151 } 152 153 if (par5 == 0) 154 { 155 if (this.tryExtend(par1World, par2, par3, par4, par6)) 156 { 157 par1World.setBlockMetadataWithNotify(par2, par3, par4, par6 | 8); 158 par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.5D, (double)par4 + 0.5D, "tile.piston.out", 0.5F, par1World.rand.nextFloat() * 0.25F + 0.6F); 159 } 160 else 161 { 162 par1World.setBlockMetadata(par2, par3, par4, par6); 163 } 164 } 165 else if (par5 == 1) 166 { 167 TileEntity var7 = par1World.getBlockTileEntity(par2 + Facing.offsetsXForSide[par6], par3 + Facing.offsetsYForSide[par6], par4 + Facing.offsetsZForSide[par6]); 168 169 if (var7 instanceof TileEntityPiston) 170 { 171 ((TileEntityPiston)var7).clearPistonTileEntity(); 172 } 173 174 par1World.setBlockAndMetadata(par2, par3, par4, Block.pistonMoving.blockID, par6); 175 par1World.setBlockTileEntity(par2, par3, par4, BlockPistonMoving.getTileEntity(this.blockID, par6, par6, false, true)); 176 177 if (this.isSticky) 178 { 179 int var8 = par2 + Facing.offsetsXForSide[par6] * 2; 180 int var9 = par3 + Facing.offsetsYForSide[par6] * 2; 181 int var10 = par4 + Facing.offsetsZForSide[par6] * 2; 182 int var11 = par1World.getBlockId(var8, var9, var10); 183 int var12 = par1World.getBlockMetadata(var8, var9, var10); 184 boolean var13 = false; 185 186 if (var11 == Block.pistonMoving.blockID) 187 { 188 TileEntity var14 = par1World.getBlockTileEntity(var8, var9, var10); 189 190 if (var14 instanceof TileEntityPiston) 191 { 192 TileEntityPiston var15 = (TileEntityPiston)var14; 193 194 if (var15.getPistonOrientation() == par6 && var15.isExtending()) 195 { 196 var15.clearPistonTileEntity(); 197 var11 = var15.getStoredBlockID(); 198 var12 = var15.getBlockMetadata(); 199 var13 = true; 200 } 201 } 202 } 203 204 if (!var13 && var11 > 0 && canPushBlock(var11, par1World, var8, var9, var10, false) && (Block.blocksList[var11].getMobilityFlag() == 0 || var11 == Block.pistonBase.blockID || var11 == Block.pistonStickyBase.blockID)) 205 { 206 par2 += Facing.offsetsXForSide[par6]; 207 par3 += Facing.offsetsYForSide[par6]; 208 par4 += Facing.offsetsZForSide[par6]; 209 par1World.setBlockAndMetadata(par2, par3, par4, Block.pistonMoving.blockID, var12); 210 par1World.setBlockTileEntity(par2, par3, par4, BlockPistonMoving.getTileEntity(var11, var12, par6, false, false)); 211 par1World.setBlockWithNotify(var8, var9, var10, 0); 212 } 213 else if (!var13) 214 { 215 par1World.setBlockWithNotify(par2 + Facing.offsetsXForSide[par6], par3 + Facing.offsetsYForSide[par6], par4 + Facing.offsetsZForSide[par6], 0); 216 } 217 } 218 else 219 { 220 par1World.setBlockWithNotify(par2 + Facing.offsetsXForSide[par6], par3 + Facing.offsetsYForSide[par6], par4 + Facing.offsetsZForSide[par6], 0); 221 } 222 223 par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.5D, (double)par4 + 0.5D, "tile.piston.in", 0.5F, par1World.rand.nextFloat() * 0.15F + 0.6F); 224 } 225 } 226 227 /** 228 * Updates the blocks bounds based on its current state. Args: world, x, y, z 229 */ 230 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 231 { 232 int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 233 234 if (isExtended(var5)) 235 { 236 switch (getOrientation(var5)) 237 { 238 case 0: 239 this.setBlockBounds(0.0F, 0.25F, 0.0F, 1.0F, 1.0F, 1.0F); 240 break; 241 case 1: 242 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.75F, 1.0F); 243 break; 244 case 2: 245 this.setBlockBounds(0.0F, 0.0F, 0.25F, 1.0F, 1.0F, 1.0F); 246 break; 247 case 3: 248 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.75F); 249 break; 250 case 4: 251 this.setBlockBounds(0.25F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 252 break; 253 case 5: 254 this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.75F, 1.0F, 1.0F); 255 } 256 } 257 else 258 { 259 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 260 } 261 } 262 263 /** 264 * Sets the block's bounds for rendering it as an item 265 */ 266 public void setBlockBoundsForItemRender() 267 { 268 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 269 } 270 271 /** 272 * if the specified block is in the given AABB, add its collision bounding box to the given list 273 */ 274 public void addCollidingBlockToList(World par1World, int par2, int par3, int par4, AxisAlignedBB par5AxisAlignedBB, List par6List, Entity par7Entity) 275 { 276 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 277 super.addCollidingBlockToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity); 278 } 279 280 /** 281 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been 282 * cleared to be reused) 283 */ 284 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 285 { 286 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 287 return super.getCollisionBoundingBoxFromPool(par1World, par2, par3, par4); 288 } 289 290 /** 291 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 292 */ 293 public boolean renderAsNormalBlock() 294 { 295 return false; 296 } 297 298 /** 299 * returns an int which describes the direction the piston faces 300 */ 301 public static int getOrientation(int par0) 302 { 303 return par0 & 7; 304 } 305 306 /** 307 * Determine if the metadata is related to something powered. 308 */ 309 public static boolean isExtended(int par0) 310 { 311 return (par0 & 8) != 0; 312 } 313 314 /** 315 * gets the way this piston should face for that entity that placed it. 316 */ 317 public static int determineOrientation(World par0World, int par1, int par2, int par3, EntityPlayer par4EntityPlayer) 318 { 319 if (MathHelper.abs((float)par4EntityPlayer.posX - (float)par1) < 2.0F && MathHelper.abs((float)par4EntityPlayer.posZ - (float)par3) < 2.0F) 320 { 321 double var5 = par4EntityPlayer.posY + 1.82D - (double)par4EntityPlayer.yOffset; 322 323 if (var5 - (double)par2 > 2.0D) 324 { 325 return 1; 326 } 327 328 if ((double)par2 - var5 > 0.0D) 329 { 330 return 0; 331 } 332 } 333 334 int var7 = MathHelper.floor_double((double)(par4EntityPlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3; 335 return var7 == 0 ? 2 : (var7 == 1 ? 5 : (var7 == 2 ? 3 : (var7 == 3 ? 4 : 0))); 336 } 337 338 /** 339 * returns true if the piston can push the specified block 340 */ 341 private static boolean canPushBlock(int par0, World par1World, int par2, int par3, int par4, boolean par5) 342 { 343 if (par0 == Block.obsidian.blockID) 344 { 345 return false; 346 } 347 else 348 { 349 if (par0 != Block.pistonBase.blockID && par0 != Block.pistonStickyBase.blockID) 350 { 351 if (Block.blocksList[par0].getBlockHardness(par1World, par2, par3, par4) == -1.0F) 352 { 353 return false; 354 } 355 356 if (Block.blocksList[par0].getMobilityFlag() == 2) 357 { 358 return false; 359 } 360 361 if (!par5 && Block.blocksList[par0].getMobilityFlag() == 1) 362 { 363 return false; 364 } 365 } 366 else if (isExtended(par1World.getBlockMetadata(par2, par3, par4))) 367 { 368 return false; 369 } 370 371 return !par1World.blockHasTileEntity(par2, par3, par4); 372 } 373 } 374 375 /** 376 * checks to see if this piston could push the blocks in front of it. 377 */ 378 private static boolean canExtend(World par0World, int par1, int par2, int par3, int par4) 379 { 380 int var5 = par1 + Facing.offsetsXForSide[par4]; 381 int var6 = par2 + Facing.offsetsYForSide[par4]; 382 int var7 = par3 + Facing.offsetsZForSide[par4]; 383 int var8 = 0; 384 385 while (true) 386 { 387 if (var8 < 13) 388 { 389 if (var6 <= 0 || var6 >= par0World.getHeight() - 1) 390 { 391 return false; 392 } 393 394 int var9 = par0World.getBlockId(var5, var6, var7); 395 396 if (var9 != 0) 397 { 398 if (!canPushBlock(var9, par0World, var5, var6, var7, true)) 399 { 400 return false; 401 } 402 403 if (Block.blocksList[var9].getMobilityFlag() != 1) 404 { 405 if (var8 == 12) 406 { 407 return false; 408 } 409 410 var5 += Facing.offsetsXForSide[par4]; 411 var6 += Facing.offsetsYForSide[par4]; 412 var7 += Facing.offsetsZForSide[par4]; 413 ++var8; 414 continue; 415 } 416 } 417 } 418 419 return true; 420 } 421 } 422 423 /** 424 * attempts to extend the piston. returns false if impossible. 425 */ 426 private boolean tryExtend(World par1World, int par2, int par3, int par4, int par5) 427 { 428 int var6 = par2 + Facing.offsetsXForSide[par5]; 429 int var7 = par3 + Facing.offsetsYForSide[par5]; 430 int var8 = par4 + Facing.offsetsZForSide[par5]; 431 int var9 = 0; 432 433 while (true) 434 { 435 int var10; 436 437 if (var9 < 13) 438 { 439 if (var7 <= 0 || var7 >= par1World.getHeight() - 1) 440 { 441 return false; 442 } 443 444 var10 = par1World.getBlockId(var6, var7, var8); 445 446 if (var10 != 0) 447 { 448 if (!canPushBlock(var10, par1World, var6, var7, var8, true)) 449 { 450 return false; 451 } 452 453 if (Block.blocksList[var10].getMobilityFlag() != 1) 454 { 455 if (var9 == 12) 456 { 457 return false; 458 } 459 460 var6 += Facing.offsetsXForSide[par5]; 461 var7 += Facing.offsetsYForSide[par5]; 462 var8 += Facing.offsetsZForSide[par5]; 463 ++var9; 464 continue; 465 } 466 467 Block.blocksList[var10].dropBlockAsItem(par1World, var6, var7, var8, par1World.getBlockMetadata(var6, var7, var8), 0); 468 par1World.setBlockWithNotify(var6, var7, var8, 0); 469 } 470 } 471 472 while (var6 != par2 || var7 != par3 || var8 != par4) 473 { 474 var9 = var6 - Facing.offsetsXForSide[par5]; 475 var10 = var7 - Facing.offsetsYForSide[par5]; 476 int var11 = var8 - Facing.offsetsZForSide[par5]; 477 int var12 = par1World.getBlockId(var9, var10, var11); 478 int var13 = par1World.getBlockMetadata(var9, var10, var11); 479 480 if (var12 == this.blockID && var9 == par2 && var10 == par3 && var11 == par4) 481 { 482 par1World.setBlockAndMetadataWithUpdate(var6, var7, var8, Block.pistonMoving.blockID, par5 | (this.isSticky ? 8 : 0), false); 483 par1World.setBlockTileEntity(var6, var7, var8, BlockPistonMoving.getTileEntity(Block.pistonExtension.blockID, par5 | (this.isSticky ? 8 : 0), par5, true, false)); 484 } 485 else 486 { 487 par1World.setBlockAndMetadataWithUpdate(var6, var7, var8, Block.pistonMoving.blockID, var13, false); 488 par1World.setBlockTileEntity(var6, var7, var8, BlockPistonMoving.getTileEntity(var12, var13, par5, true, false)); 489 } 490 491 var6 = var9; 492 var7 = var10; 493 var8 = var11; 494 } 495 496 return true; 497 } 498 } 499 }