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