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(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
440        {
441            return !this.wiresProvidePower ? false : this.isPoweringTo(par1IBlockAccess, 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    }