    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    }