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    }