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