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    }