    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.Random;
    006
    007    public class BlockRedstoneRepeater extends BlockDirectional
    008    {
    009        /** The offsets for the two torches in redstone repeater blocks. */
    010        public static final double[] repeaterTorchOffset = new double[] { -0.0625D, 0.0625D, 0.1875D, 0.3125D};
    011
    012        /** The states in which the redstone repeater blocks can be. */
    013        private static final int[] repeaterState = new int[] {1, 2, 3, 4};
    014
    015        /** Tells whether the repeater is powered or not */
    016        private final boolean isRepeaterPowered;
    017
    018        protected BlockRedstoneRepeater(int par1, boolean par2)
    019        {
    020            super(par1, 6, Material.circuits);
    021            this.isRepeaterPowered = par2;
    022            this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
    023        }
    024
    025        /**
    026         * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
    027         */
    028        public boolean renderAsNormalBlock()
    029        {
    030            return false;
    031        }
    032
    033        /**
    034         * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
    035         */
    036        public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
    037        {
    038            return !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) ? false : super.canPlaceBlockAt(par1World, par2, par3, par4);
    039        }
    040
    041        /**
    042         * Can this block stay at this position.  Similar to canPlaceBlockAt except gets checked often with plants.
    043         */
    044        public boolean canBlockStay(World par1World, int par2, int par3, int par4)
    045        {
    046            return !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) ? false : super.canBlockStay(par1World, par2, par3, par4);
    047        }
    048
    049        /**
    050         * Ticks the block if it's been scheduled
    051         */
    052        public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
    053        {
    054            int var6 = par1World.getBlockMetadata(par2, par3, par4);
    055            boolean var7 = this.func_82523_e(par1World, par2, par3, par4, var6);
    056
    057            if (!var7)
    058            {
    059                boolean var8 = this.ignoreTick(par1World, par2, par3, par4, var6);
    060
    061                if (this.isRepeaterPowered && !var8)
    062                {
    063                    par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterIdle.blockID, var6);
    064                }
    065                else if (!this.isRepeaterPowered)
    066                {
    067                    par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterActive.blockID, var6);
    068
    069                    if (!var8)
    070                    {
    071                        int var9 = (var6 & 12) >> 2;
    072                        par1World.scheduleBlockUpdate(par2, par3, par4, Block.redstoneRepeaterActive.blockID, repeaterState[var9] * 2);
    073                    }
    074                }
    075            }
    076        }
    077
    078        /**
    079         * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
    080         */
    081        public int getBlockTextureFromSideAndMetadata(int par1, int par2)
    082        {
    083            return par1 == 0 ? (this.isRepeaterPowered ? 99 : 115) : (par1 == 1 ? (this.isRepeaterPowered ? 147 : 131) : 5);
    084        }
    085
    086        @SideOnly(Side.CLIENT)
    087
    088        /**
    089         * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
    090         * coordinates.  Args: blockAccess, x, y, z, side
    091         */
    092        public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    093        {
    094            return par5 != 0 && par5 != 1;
    095        }
    096
    097        /**
    098         * The type of render function that is called for this block
    099         */
    100        public int getRenderType()
    101        {
    102            return 15;
    103        }
    104
    105        /**
    106         * Returns the block texture based on the side being looked at.  Args: side
    107         */
    108        public int getBlockTextureFromSide(int par1)
    109        {
    110            return this.getBlockTextureFromSideAndMetadata(par1, 0);
    111        }
    112
    113        /**
    114         * Is this block indirectly powering the block on the specified side
    115         */
    116        public boolean isIndirectlyPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    117        {
    118            return this.isPoweringTo(par1IBlockAccess, par2, par3, par4, par5);
    119        }
    120
    121        /**
    122         * Is this block powering the block on the specified side
    123         */
    124        public boolean isPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    125        {
    126            if (!this.isRepeaterPowered)
    127            {
    128                return false;
    129            }
    130            else
    131            {
    132                int var6 = getDirection(par1IBlockAccess.getBlockMetadata(par2, par3, par4));
    133                return var6 == 0 && par5 == 3 ? true : (var6 == 1 && par5 == 4 ? true : (var6 == 2 && par5 == 2 ? true : var6 == 3 && par5 == 5));
    134            }
    135        }
    136
    137        /**
    138         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
    139         * their own) Args: x, y, z, neighbor blockID
    140         */
    141        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
    142        {
    143            if (!this.canBlockStay(par1World, par2, par3, par4))
    144            {
    145                this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
    146                par1World.setBlockWithNotify(par2, par3, par4, 0);
    147                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
    148                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
    149                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
    150                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
    151                par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
    152                par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
    153            }
    154            else
    155            {
    156                int var6 = par1World.getBlockMetadata(par2, par3, par4);
    157                boolean var7 = this.func_82523_e(par1World, par2, par3, par4, var6);
    158
    159                if (!var7)
    160                {
    161                    boolean var8 = this.ignoreTick(par1World, par2, par3, par4, var6);
    162                    int var9 = (var6 & 12) >> 2;
    163
    164                    if (this.isRepeaterPowered && !var8 || !this.isRepeaterPowered && var8)
    165                    {
    166                        byte var10 = 0;
    167
    168                        if (this.func_83011_d(par1World, par2, par3, par4, var6))
    169                        {
    170                            var10 = -1;
    171                        }
    172
    173                        par1World.func_82740_a(par2, par3, par4, this.blockID, repeaterState[var9] * 2, var10);
    174                    }
    175                }
    176            }
    177        }
    178
    179        private boolean ignoreTick(World par1World, int par2, int par3, int par4, int par5)
    180        {
    181            int var6 = getDirection(par5);
    182
    183            switch (var6)
    184            {
    185                case 0:
    186                    return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 + 1, 3) || par1World.getBlockId(par2, par3, par4 + 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 + 1) > 0;
    187                case 1:
    188                    return par1World.isBlockIndirectlyProvidingPowerTo(par2 - 1, par3, par4, 4) || par1World.getBlockId(par2 - 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 - 1, par3, par4) > 0;
    189                case 2:
    190                    return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 - 1, 2) || par1World.getBlockId(par2, par3, par4 - 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 - 1) > 0;
    191                case 3:
    192                    return par1World.isBlockIndirectlyProvidingPowerTo(par2 + 1, par3, par4, 5) || par1World.getBlockId(par2 + 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 + 1, par3, par4) > 0;
    193                default:
    194                    return false;
    195            }
    196        }
    197
    198        public boolean func_82523_e(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    199        {
    200            int var6 = getDirection(par5);
    201
    202            switch (var6)
    203            {
    204                case 0:
    205                case 2:
    206                    return par1IBlockAccess.isBlockProvidingPowerTo(par2 - 1, par3, par4, 4) && func_82524_c(par1IBlockAccess.getBlockId(par2 - 1, par3, par4)) || par1IBlockAccess.isBlockProvidingPowerTo(par2 + 1, par3, par4, 5) && func_82524_c(par1IBlockAccess.getBlockId(par2 + 1, par3, par4));
    207                case 1:
    208                case 3:
    209                    return par1IBlockAccess.isBlockProvidingPowerTo(par2, par3, par4 + 1, 3) && func_82524_c(par1IBlockAccess.getBlockId(par2, par3, par4 + 1)) || par1IBlockAccess.isBlockProvidingPowerTo(par2, par3, par4 - 1, 2) && func_82524_c(par1IBlockAccess.getBlockId(par2, par3, par4 - 1));
    210                default:
    211                    return false;
    212            }
    213        }
    214
    215        /**
    216         * Called upon block activation (right click on the block.)
    217         */
    218        public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    219        {
    220            int var10 = par1World.getBlockMetadata(par2, par3, par4);
    221            int var11 = (var10 & 12) >> 2;
    222            var11 = var11 + 1 << 2 & 12;
    223            par1World.setBlockMetadataWithNotify(par2, par3, par4, var11 | var10 & 3);
    224            return true;
    225        }
    226
    227        /**
    228         * Can this block provide power. Only wire currently seems to have this change based on its state.
    229         */
    230        public boolean canProvidePower()
    231        {
    232            return true;
    233        }
    234
    235        /**
    236         * Called when the block is placed in the world.
    237         */
    238        public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving)
    239        {
    240            int var6 = ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4;
    241            par1World.setBlockMetadataWithNotify(par2, par3, par4, var6);
    242            boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6);
    243
    244            if (var7)
    245            {
    246                par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, 1);
    247            }
    248        }
    249
    250        /**
    251         * Called whenever the block is added into the world. Args: world, x, y, z
    252         */
    253        public void onBlockAdded(World par1World, int par2, int par3, int par4)
    254        {
    255            par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
    256            par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
    257            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
    258            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
    259            par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
    260            par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
    261        }
    262
    263        /**
    264         * Called right before the block is destroyed by a player.  Args: world, x, y, z, metaData
    265         */
    266        public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5)
    267        {
    268            if (this.isRepeaterPowered)
    269            {
    270                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
    271                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
    272                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
    273                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
    274                par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
    275                par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
    276            }
    277
    278            super.onBlockDestroyedByPlayer(par1World, par2, par3, par4, par5);
    279        }
    280
    281        /**
    282         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    283         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    284         */
    285        public boolean isOpaqueCube()
    286        {
    287            return false;
    288        }
    289
    290        /**
    291         * Returns the ID of the items to drop on destruction.
    292         */
    293        public int idDropped(int par1, Random par2Random, int par3)
    294        {
    295            return Item.redstoneRepeater.shiftedIndex;
    296        }
    297
    298        @SideOnly(Side.CLIENT)
    299
    300        /**
    301         * A randomly called display update to be able to add particles or other items for display
    302         */
    303        public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
    304        {
    305            if (this.isRepeaterPowered)
    306            {
    307                int var6 = par1World.getBlockMetadata(par2, par3, par4);
    308                int var7 = getDirection(var6);
    309                double var8 = (double)((float)par2 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    310                double var10 = (double)((float)par3 + 0.4F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    311                double var12 = (double)((float)par4 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    312                double var14 = 0.0D;
    313                double var16 = 0.0D;
    314
    315                if (par5Random.nextInt(2) == 0)
    316                {
    317                    switch (var7)
    318                    {
    319                        case 0:
    320                            var16 = -0.3125D;
    321                            break;
    322                        case 1:
    323                            var14 = 0.3125D;
    324                            break;
    325                        case 2:
    326                            var16 = 0.3125D;
    327                            break;
    328                        case 3:
    329                            var14 = -0.3125D;
    330                    }
    331                }
    332                else
    333                {
    334                    int var18 = (var6 & 12) >> 2;
    335
    336                    switch (var7)
    337                    {
    338                        case 0:
    339                            var16 = repeaterTorchOffset[var18];
    340                            break;
    341                        case 1:
    342                            var14 = -repeaterTorchOffset[var18];
    343                            break;
    344                        case 2:
    345                            var16 = -repeaterTorchOffset[var18];
    346                            break;
    347                        case 3:
    348                            var14 = repeaterTorchOffset[var18];
    349                    }
    350                }
    351
    352                par1World.spawnParticle("reddust", var8 + var14, var10, var12 + var16, 0.0D, 0.0D, 0.0D);
    353            }
    354        }
    355
    356        @SideOnly(Side.CLIENT)
    357
    358        /**
    359         * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
    360         */
    361        public int idPicked(World par1World, int par2, int par3, int par4)
    362        {
    363            return Item.redstoneRepeater.shiftedIndex;
    364        }
    365
    366        public static boolean func_82524_c(int par0)
    367        {
    368            return par0 == Block.redstoneRepeaterActive.blockID || par0 == Block.redstoneRepeaterIdle.blockID;
    369        }
    370
    371        public boolean func_83011_d(World par1World, int par2, int par3, int par4, int par5)
    372        {
    373            int var6 = getDirection(par5);
    374
    375            if (func_82524_c(par1World.getBlockId(par2 - Direction.offsetX[var6], par3, par4 - Direction.offsetZ[var6])))
    376            {
    377                int var7 = par1World.getBlockMetadata(par2 - Direction.offsetX[var6], par3, par4 - Direction.offsetZ[var6]);
    378                int var8 = getDirection(var7);
    379                return var8 != var6;
    380            }
    381            else
    382            {
    383                return false;
    384            }
    385        }
    386    }