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.ArrayList; 006 import java.util.HashSet; 007 import java.util.Random; 008 import java.util.Set; 009 010 public class BlockRedstoneWire extends Block 011 { 012 /** 013 * When false, power transmission methods do not look at other redstone wires. Used internally during 014 * updateCurrentStrength. 015 */ 016 private boolean wiresProvidePower = true; 017 private Set blocksNeedingUpdate = new HashSet(); 018 019 public BlockRedstoneWire(int par1, int par2) 020 { 021 super(par1, par2, Material.circuits); 022 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.0625F, 1.0F); 023 } 024 025 /** 026 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 027 */ 028 public int getBlockTextureFromSideAndMetadata(int par1, int par2) 029 { 030 return this.blockIndexInTexture; 031 } 032 033 /** 034 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been 035 * cleared to be reused) 036 */ 037 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 038 { 039 return null; 040 } 041 042 /** 043 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 044 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 045 */ 046 public boolean isOpaqueCube() 047 { 048 return false; 049 } 050 051 /** 052 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 053 */ 054 public boolean renderAsNormalBlock() 055 { 056 return false; 057 } 058 059 /** 060 * The type of render function that is called for this block 061 */ 062 public int getRenderType() 063 { 064 return 5; 065 } 066 067 @SideOnly(Side.CLIENT) 068 069 /** 070 * Returns a integer with hex for 0xrrggbb with this color multiplied against the blocks color. Note only called 071 * when first determining what to render. 072 */ 073 public int colorMultiplier(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 074 { 075 return 8388608; 076 } 077 078 /** 079 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 080 */ 081 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 082 { 083 return par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) || par1World.getBlockId(par2, par3 - 1, par4) == Block.glowStone.blockID; 084 } 085 086 /** 087 * Sets the strength of the wire current (0-15) for this block based on neighboring blocks and propagates to 088 * neighboring redstone wires 089 */ 090 private void updateAndPropagateCurrentStrength(World par1World, int par2, int par3, int par4) 091 { 092 this.calculateCurrentChanges(par1World, par2, par3, par4, par2, par3, par4); 093 ArrayList var5 = new ArrayList(this.blocksNeedingUpdate); 094 this.blocksNeedingUpdate.clear(); 095 096 for (int var6 = 0; var6 < var5.size(); ++var6) 097 { 098 ChunkPosition var7 = (ChunkPosition)var5.get(var6); 099 par1World.notifyBlocksOfNeighborChange(var7.x, var7.y, var7.z, this.blockID); 100 } 101 } 102 103 private void calculateCurrentChanges(World par1World, int par2, int par3, int par4, int par5, int par6, int par7) 104 { 105 int var8 = par1World.getBlockMetadata(par2, par3, par4); 106 int var9 = 0; 107 this.wiresProvidePower = false; 108 boolean var10 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4); 109 this.wiresProvidePower = true; 110 int var11; 111 int var12; 112 int var13; 113 114 if (var10) 115 { 116 var9 = 15; 117 } 118 else 119 { 120 for (var11 = 0; var11 < 4; ++var11) 121 { 122 var12 = par2; 123 var13 = par4; 124 125 if (var11 == 0) 126 { 127 var12 = par2 - 1; 128 } 129 130 if (var11 == 1) 131 { 132 ++var12; 133 } 134 135 if (var11 == 2) 136 { 137 var13 = par4 - 1; 138 } 139 140 if (var11 == 3) 141 { 142 ++var13; 143 } 144 145 if (var12 != par5 || par3 != par6 || var13 != par7) 146 { 147 var9 = this.getMaxCurrentStrength(par1World, var12, par3, var13, var9); 148 } 149 150 if (par1World.isBlockNormalCube(var12, par3, var13) && !par1World.isBlockNormalCube(par2, par3 + 1, par4)) 151 { 152 if (var12 != par5 || par3 + 1 != par6 || var13 != par7) 153 { 154 var9 = this.getMaxCurrentStrength(par1World, var12, par3 + 1, var13, var9); 155 } 156 } 157 else if (!par1World.isBlockNormalCube(var12, par3, var13) && (var12 != par5 || par3 - 1 != par6 || var13 != par7)) 158 { 159 var9 = this.getMaxCurrentStrength(par1World, var12, par3 - 1, var13, var9); 160 } 161 } 162 163 if (var9 > 0) 164 { 165 --var9; 166 } 167 else 168 { 169 var9 = 0; 170 } 171 } 172 173 if (var8 != var9) 174 { 175 par1World.editingBlocks = true; 176 par1World.setBlockMetadataWithNotify(par2, par3, par4, var9); 177 par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4); 178 par1World.editingBlocks = false; 179 180 for (var11 = 0; var11 < 4; ++var11) 181 { 182 var12 = par2; 183 var13 = par4; 184 int var14 = par3 - 1; 185 186 if (var11 == 0) 187 { 188 var12 = par2 - 1; 189 } 190 191 if (var11 == 1) 192 { 193 ++var12; 194 } 195 196 if (var11 == 2) 197 { 198 var13 = par4 - 1; 199 } 200 201 if (var11 == 3) 202 { 203 ++var13; 204 } 205 206 if (par1World.isBlockNormalCube(var12, par3, var13)) 207 { 208 var14 += 2; 209 } 210 211 boolean var15 = false; 212 int var16 = this.getMaxCurrentStrength(par1World, var12, par3, var13, -1); 213 var9 = par1World.getBlockMetadata(par2, par3, par4); 214 215 if (var9 > 0) 216 { 217 --var9; 218 } 219 220 if (var16 >= 0 && var16 != var9) 221 { 222 this.calculateCurrentChanges(par1World, var12, par3, var13, par2, par3, par4); 223 } 224 225 var16 = this.getMaxCurrentStrength(par1World, var12, var14, var13, -1); 226 var9 = par1World.getBlockMetadata(par2, par3, par4); 227 228 if (var9 > 0) 229 { 230 --var9; 231 } 232 233 if (var16 >= 0 && var16 != var9) 234 { 235 this.calculateCurrentChanges(par1World, var12, var14, var13, par2, par3, par4); 236 } 237 } 238 239 if (var8 < var9 || var9 == 0) 240 { 241 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3, par4)); 242 this.blocksNeedingUpdate.add(new ChunkPosition(par2 - 1, par3, par4)); 243 this.blocksNeedingUpdate.add(new ChunkPosition(par2 + 1, par3, par4)); 244 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3 - 1, par4)); 245 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3 + 1, par4)); 246 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3, par4 - 1)); 247 this.blocksNeedingUpdate.add(new ChunkPosition(par2, par3, par4 + 1)); 248 } 249 } 250 } 251 252 /** 253 * Calls World.notifyBlocksOfNeighborChange() for all neighboring blocks, but only if the given block is a redstone 254 * wire. 255 */ 256 private void notifyWireNeighborsOfNeighborChange(World par1World, int par2, int par3, int par4) 257 { 258 if (par1World.getBlockId(par2, par3, par4) == this.blockID) 259 { 260 par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID); 261 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 262 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 263 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 264 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 265 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 266 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 267 } 268 } 269 270 /** 271 * Called whenever the block is added into the world. Args: world, x, y, z 272 */ 273 public void onBlockAdded(World par1World, int par2, int par3, int par4) 274 { 275 super.onBlockAdded(par1World, par2, par3, par4); 276 277 if (!par1World.isRemote) 278 { 279 this.updateAndPropagateCurrentStrength(par1World, par2, par3, par4); 280 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 281 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 282 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3, par4); 283 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3, par4); 284 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3, par4 - 1); 285 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3, par4 + 1); 286 287 if (par1World.isBlockNormalCube(par2 - 1, par3, par4)) 288 { 289 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3 + 1, par4); 290 } 291 else 292 { 293 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3 - 1, par4); 294 } 295 296 if (par1World.isBlockNormalCube(par2 + 1, par3, par4)) 297 { 298 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3 + 1, par4); 299 } 300 else 301 { 302 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3 - 1, par4); 303 } 304 305 if (par1World.isBlockNormalCube(par2, par3, par4 - 1)) 306 { 307 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 + 1, par4 - 1); 308 } 309 else 310 { 311 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 - 1, par4 - 1); 312 } 313 314 if (par1World.isBlockNormalCube(par2, par3, par4 + 1)) 315 { 316 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 + 1, par4 + 1); 317 } 318 else 319 { 320 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 - 1, par4 + 1); 321 } 322 } 323 } 324 325 /** 326 * ejects contained items into the world, and notifies neighbours of an update, as appropriate 327 */ 328 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) 329 { 330 super.breakBlock(par1World, par2, par3, par4, par5, par6); 331 332 if (!par1World.isRemote) 333 { 334 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 335 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 336 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 337 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 338 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 339 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 340 this.updateAndPropagateCurrentStrength(par1World, par2, par3, par4); 341 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3, par4); 342 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3, par4); 343 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3, par4 - 1); 344 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3, par4 + 1); 345 346 if (par1World.isBlockNormalCube(par2 - 1, par3, par4)) 347 { 348 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3 + 1, par4); 349 } 350 else 351 { 352 this.notifyWireNeighborsOfNeighborChange(par1World, par2 - 1, par3 - 1, par4); 353 } 354 355 if (par1World.isBlockNormalCube(par2 + 1, par3, par4)) 356 { 357 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3 + 1, par4); 358 } 359 else 360 { 361 this.notifyWireNeighborsOfNeighborChange(par1World, par2 + 1, par3 - 1, par4); 362 } 363 364 if (par1World.isBlockNormalCube(par2, par3, par4 - 1)) 365 { 366 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 + 1, par4 - 1); 367 } 368 else 369 { 370 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 - 1, par4 - 1); 371 } 372 373 if (par1World.isBlockNormalCube(par2, par3, par4 + 1)) 374 { 375 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 + 1, par4 + 1); 376 } 377 else 378 { 379 this.notifyWireNeighborsOfNeighborChange(par1World, par2, par3 - 1, par4 + 1); 380 } 381 } 382 } 383 384 /** 385 * Returns the current strength at the specified block if it is greater than the passed value, or the passed value 386 * otherwise. Signature: (world, x, y, z, strength) 387 */ 388 private int getMaxCurrentStrength(World par1World, int par2, int par3, int par4, int par5) 389 { 390 if (par1World.getBlockId(par2, par3, par4) != this.blockID) 391 { 392 return par5; 393 } 394 else 395 { 396 int var6 = par1World.getBlockMetadata(par2, par3, par4); 397 return var6 > par5 ? var6 : par5; 398 } 399 } 400 401 /** 402 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 403 * their own) Args: x, y, z, neighbor blockID 404 */ 405 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 406 { 407 if (!par1World.isRemote) 408 { 409 int var6 = par1World.getBlockMetadata(par2, par3, par4); 410 boolean var7 = this.canPlaceBlockAt(par1World, par2, par3, par4); 411 412 if (var7) 413 { 414 this.updateAndPropagateCurrentStrength(par1World, par2, par3, par4); 415 } 416 else 417 { 418 this.dropBlockAsItem(par1World, par2, par3, par4, var6, 0); 419 par1World.setBlockWithNotify(par2, par3, par4, 0); 420 } 421 422 super.onNeighborBlockChange(par1World, par2, par3, par4, par5); 423 } 424 } 425 426 /** 427 * Returns the ID of the items to drop on destruction. 428 */ 429 public int idDropped(int par1, Random par2Random, int par3) 430 { 431 return Item.redstone.shiftedIndex; 432 } 433 434 /** 435 * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z, 436 * side 437 */ 438 public boolean isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 439 { 440 return !this.wiresProvidePower ? false : this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5); 441 } 442 443 /** 444 * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube 445 * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X, 446 * Y, Z, side 447 */ 448 public boolean isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 449 { 450 if (!this.wiresProvidePower) 451 { 452 return false; 453 } 454 else if (par1IBlockAccess.getBlockMetadata(par2, par3, par4) == 0) 455 { 456 return false; 457 } 458 else if (par5 == 1) 459 { 460 return true; 461 } 462 else 463 { 464 boolean var6 = isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3, par4, 1) || !par1IBlockAccess.isBlockNormalCube(par2 - 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3 - 1, par4, -1); 465 boolean var7 = isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3, par4, 3) || !par1IBlockAccess.isBlockNormalCube(par2 + 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3 - 1, par4, -1); 466 boolean var8 = isPoweredOrRepeater(par1IBlockAccess, par2, par3, par4 - 1, 2) || !par1IBlockAccess.isBlockNormalCube(par2, par3, par4 - 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 - 1, par4 - 1, -1); 467 boolean var9 = isPoweredOrRepeater(par1IBlockAccess, par2, par3, par4 + 1, 0) || !par1IBlockAccess.isBlockNormalCube(par2, par3, par4 + 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 - 1, par4 + 1, -1); 468 469 if (!par1IBlockAccess.isBlockNormalCube(par2, par3 + 1, par4)) 470 { 471 if (par1IBlockAccess.isBlockNormalCube(par2 - 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3 + 1, par4, -1)) 472 { 473 var6 = true; 474 } 475 476 if (par1IBlockAccess.isBlockNormalCube(par2 + 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3 + 1, par4, -1)) 477 { 478 var7 = true; 479 } 480 481 if (par1IBlockAccess.isBlockNormalCube(par2, par3, par4 - 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 + 1, par4 - 1, -1)) 482 { 483 var8 = true; 484 } 485 486 if (par1IBlockAccess.isBlockNormalCube(par2, par3, par4 + 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 + 1, par4 + 1, -1)) 487 { 488 var9 = true; 489 } 490 } 491 492 return !var8 && !var7 && !var6 && !var9 && par5 >= 2 && par5 <= 5 ? true : (par5 == 2 && var8 && !var6 && !var7 ? true : (par5 == 3 && var9 && !var6 && !var7 ? true : (par5 == 4 && var6 && !var8 && !var9 ? true : par5 == 5 && var7 && !var8 && !var9))); 493 } 494 } 495 496 /** 497 * Can this block provide power. Only wire currently seems to have this change based on its state. 498 */ 499 public boolean canProvidePower() 500 { 501 return this.wiresProvidePower; 502 } 503 504 @SideOnly(Side.CLIENT) 505 506 /** 507 * A randomly called display update to be able to add particles or other items for display 508 */ 509 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random) 510 { 511 int var6 = par1World.getBlockMetadata(par2, par3, par4); 512 513 if (var6 > 0) 514 { 515 double var7 = (double)par2 + 0.5D + ((double)par5Random.nextFloat() - 0.5D) * 0.2D; 516 double var9 = (double)((float)par3 + 0.0625F); 517 double var11 = (double)par4 + 0.5D + ((double)par5Random.nextFloat() - 0.5D) * 0.2D; 518 float var13 = (float)var6 / 15.0F; 519 float var14 = var13 * 0.6F + 0.4F; 520 521 if (var6 == 0) 522 { 523 var14 = 0.0F; 524 } 525 526 float var15 = var13 * var13 * 0.7F - 0.5F; 527 float var16 = var13 * var13 * 0.6F - 0.7F; 528 529 if (var15 < 0.0F) 530 { 531 var15 = 0.0F; 532 } 533 534 if (var16 < 0.0F) 535 { 536 var16 = 0.0F; 537 } 538 539 par1World.spawnParticle("reddust", var7, var9, var11, (double)var14, (double)var15, (double)var16); 540 } 541 } 542 543 /** 544 * Returns true if the block coordinate passed can provide power, or is a redstone wire. 545 */ 546 public static boolean isPowerProviderOrWire(IBlockAccess par0IBlockAccess, int par1, int par2, int par3, int par4) 547 { 548 int var5 = par0IBlockAccess.getBlockId(par1, par2, par3); 549 550 if (var5 == Block.redstoneWire.blockID) 551 { 552 return true; 553 } 554 else if (var5 == 0) 555 { 556 return false; 557 } 558 else if (var5 != Block.redstoneRepeaterIdle.blockID && var5 != Block.redstoneRepeaterActive.blockID) 559 { 560 return (Block.blocksList[var5] != null && Block.blocksList[var5].canConnectRedstone(par0IBlockAccess, par1, par2, par3, par4)); 561 } 562 else 563 { 564 int var6 = par0IBlockAccess.getBlockMetadata(par1, par2, par3); 565 return par4 == (var6 & 3) || par4 == Direction.footInvisibleFaceRemap[var6 & 3]; 566 } 567 } 568 569 /** 570 * Returns true if the block coordinate passed can provide power, or is a redstone wire, or if its a repeater that 571 * is powered. 572 */ 573 public static boolean isPoweredOrRepeater(IBlockAccess par0IBlockAccess, int par1, int par2, int par3, int par4) 574 { 575 if (isPowerProviderOrWire(par0IBlockAccess, par1, par2, par3, par4)) 576 { 577 return true; 578 } 579 else 580 { 581 int var5 = par0IBlockAccess.getBlockId(par1, par2, par3); 582 583 if (var5 == Block.redstoneRepeaterActive.blockID) 584 { 585 int var6 = par0IBlockAccess.getBlockMetadata(par1, par2, par3); 586 return par4 == (var6 & 3); 587 } 588 else 589 { 590 return false; 591 } 592 } 593 } 594 595 @SideOnly(Side.CLIENT) 596 597 /** 598 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) 599 */ 600 public int idPicked(World par1World, int par2, int par3, int par4) 601 { 602 return Item.redstone.shiftedIndex; 603 } 604 }