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.markBlocksDirty(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 * Is this block indirectly powering the block on the specified side
436 */
437 public boolean isIndirectlyPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
438 {
439 return !this.wiresProvidePower ? false : this.isPoweringTo(par1IBlockAccess, par2, par3, par4, par5);
440 }
441
442 /**
443 * Is this block powering the block on the specified side
444 */
445 public boolean isPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
446 {
447 if (!this.wiresProvidePower)
448 {
449 return false;
450 }
451 else if (par1IBlockAccess.getBlockMetadata(par2, par3, par4) == 0)
452 {
453 return false;
454 }
455 else if (par5 == 1)
456 {
457 return true;
458 }
459 else
460 {
461 boolean var6 = isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3, par4, 1) || !par1IBlockAccess.isBlockNormalCube(par2 - 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3 - 1, par4, -1);
462 boolean var7 = isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3, par4, 3) || !par1IBlockAccess.isBlockNormalCube(par2 + 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3 - 1, par4, -1);
463 boolean var8 = isPoweredOrRepeater(par1IBlockAccess, par2, par3, par4 - 1, 2) || !par1IBlockAccess.isBlockNormalCube(par2, par3, par4 - 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 - 1, par4 - 1, -1);
464 boolean var9 = isPoweredOrRepeater(par1IBlockAccess, par2, par3, par4 + 1, 0) || !par1IBlockAccess.isBlockNormalCube(par2, par3, par4 + 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 - 1, par4 + 1, -1);
465
466 if (!par1IBlockAccess.isBlockNormalCube(par2, par3 + 1, par4))
467 {
468 if (par1IBlockAccess.isBlockNormalCube(par2 - 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 - 1, par3 + 1, par4, -1))
469 {
470 var6 = true;
471 }
472
473 if (par1IBlockAccess.isBlockNormalCube(par2 + 1, par3, par4) && isPoweredOrRepeater(par1IBlockAccess, par2 + 1, par3 + 1, par4, -1))
474 {
475 var7 = true;
476 }
477
478 if (par1IBlockAccess.isBlockNormalCube(par2, par3, par4 - 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 + 1, par4 - 1, -1))
479 {
480 var8 = true;
481 }
482
483 if (par1IBlockAccess.isBlockNormalCube(par2, par3, par4 + 1) && isPoweredOrRepeater(par1IBlockAccess, par2, par3 + 1, par4 + 1, -1))
484 {
485 var9 = true;
486 }
487 }
488
489 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)));
490 }
491 }
492
493 /**
494 * Can this block provide power. Only wire currently seems to have this change based on its state.
495 */
496 public boolean canProvidePower()
497 {
498 return this.wiresProvidePower;
499 }
500
501 @SideOnly(Side.CLIENT)
502
503 /**
504 * A randomly called display update to be able to add particles or other items for display
505 */
506 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
507 {
508 int var6 = par1World.getBlockMetadata(par2, par3, par4);
509
510 if (var6 > 0)
511 {
512 double var7 = (double)par2 + 0.5D + ((double)par5Random.nextFloat() - 0.5D) * 0.2D;
513 double var9 = (double)((float)par3 + 0.0625F);
514 double var11 = (double)par4 + 0.5D + ((double)par5Random.nextFloat() - 0.5D) * 0.2D;
515 float var13 = (float)var6 / 15.0F;
516 float var14 = var13 * 0.6F + 0.4F;
517
518 if (var6 == 0)
519 {
520 var14 = 0.0F;
521 }
522
523 float var15 = var13 * var13 * 0.7F - 0.5F;
524 float var16 = var13 * var13 * 0.6F - 0.7F;
525
526 if (var15 < 0.0F)
527 {
528 var15 = 0.0F;
529 }
530
531 if (var16 < 0.0F)
532 {
533 var16 = 0.0F;
534 }
535
536 par1World.spawnParticle("reddust", var7, var9, var11, (double)var14, (double)var15, (double)var16);
537 }
538 }
539
540 /**
541 * Returns true if the block coordinate passed can provide power, or is a redstone wire.
542 */
543 public static boolean isPowerProviderOrWire(IBlockAccess par0IBlockAccess, int par1, int par2, int par3, int par4)
544 {
545 int var5 = par0IBlockAccess.getBlockId(par1, par2, par3);
546
547 if (var5 == Block.redstoneWire.blockID)
548 {
549 return true;
550 }
551 else if (var5 == 0)
552 {
553 return false;
554 }
555 else if (var5 != Block.redstoneRepeaterIdle.blockID && var5 != Block.redstoneRepeaterActive.blockID)
556 {
557 return (Block.blocksList[var5] != null && Block.blocksList[var5].canConnectRedstone(par0IBlockAccess, par1, par2, par3, par4));
558 }
559 else
560 {
561 int var6 = par0IBlockAccess.getBlockMetadata(par1, par2, par3);
562 return par4 == (var6 & 3) || par4 == Direction.footInvisibleFaceRemap[var6 & 3];
563 }
564 }
565
566 /**
567 * Returns true if the block coordinate passed can provide power, or is a redstone wire, or if its a repeater that
568 * is powered.
569 */
570 public static boolean isPoweredOrRepeater(IBlockAccess par0IBlockAccess, int par1, int par2, int par3, int par4)
571 {
572 if (isPowerProviderOrWire(par0IBlockAccess, par1, par2, par3, par4))
573 {
574 return true;
575 }
576 else
577 {
578 int var5 = par0IBlockAccess.getBlockId(par1, par2, par3);
579
580 if (var5 == Block.redstoneRepeaterActive.blockID)
581 {
582 int var6 = par0IBlockAccess.getBlockMetadata(par1, par2, par3);
583 return par4 == (var6 & 3);
584 }
585 else
586 {
587 return false;
588 }
589 }
590 }
591
592 @SideOnly(Side.CLIENT)
593
594 /**
595 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
596 */
597 public int idPicked(World par1World, int par2, int par3, int par4)
598 {
599 return Item.redstone.shiftedIndex;
600 }
601 }