    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                        int var11 = getDirection(var6);
    168
    169                        if (func_82524_c(par1World.getBlockId(par2 - Direction.offsetX[var11], par3, par4 - Direction.offsetZ[var11])))
    170                        {
    171                            var10 = -1;
    172                        }
    173
    174                        par1World.func_82740_a(par2, par3, par4, this.blockID, repeaterState[var9] * 2, var10);
    175                    }
    176                }
    177            }
    178        }
    179
    180        private boolean ignoreTick(World par1World, int par2, int par3, int par4, int par5)
    181        {
    182            int var6 = getDirection(par5);
    183
    184            switch (var6)
    185            {
    186                case 0:
    187                    return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 + 1, 3) || par1World.getBlockId(par2, par3, par4 + 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 + 1) > 0;
    188                case 1:
    189                    return par1World.isBlockIndirectlyProvidingPowerTo(par2 - 1, par3, par4, 4) || par1World.getBlockId(par2 - 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 - 1, par3, par4) > 0;
    190                case 2:
    191                    return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 - 1, 2) || par1World.getBlockId(par2, par3, par4 - 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 - 1) > 0;
    192                case 3:
    193                    return par1World.isBlockIndirectlyProvidingPowerTo(par2 + 1, par3, par4, 5) || par1World.getBlockId(par2 + 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 + 1, par3, par4) > 0;
    194                default:
    195                    return false;
    196            }
    197        }
    198
    199        public boolean func_82523_e(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    200        {
    201            int var6 = getDirection(par5);
    202
    203            switch (var6)
    204            {
    205                case 0:
    206                case 2:
    207                    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));
    208                case 1:
    209                case 3:
    210                    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));
    211                default:
    212                    return false;
    213            }
    214        }
    215
    216        /**
    217         * Called upon block activation (right click on the block.)
    218         */
    219        public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    220        {
    221            int var10 = par1World.getBlockMetadata(par2, par3, par4);
    222            int var11 = (var10 & 12) >> 2;
    223            var11 = var11 + 1 << 2 & 12;
    224            par1World.setBlockMetadataWithNotify(par2, par3, par4, var11 | var10 & 3);
    225            return true;
    226        }
    227
    228        /**
    229         * Can this block provide power. Only wire currently seems to have this change based on its state.
    230         */
    231        public boolean canProvidePower()
    232        {
    233            return true;
    234        }
    235
    236        /**
    237         * Called when the block is placed in the world.
    238         */
    239        public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving)
    240        {
    241            int var6 = ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4;
    242            par1World.setBlockMetadataWithNotify(par2, par3, par4, var6);
    243            boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6);
    244
    245            if (var7)
    246            {
    247                par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, 1);
    248            }
    249        }
    250
    251        /**
    252         * Called whenever the block is added into the world. Args: world, x, y, z
    253         */
    254        public void onBlockAdded(World par1World, int par2, int par3, int par4)
    255        {
    256            par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
    257            par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
    258            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
    259            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
    260            par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
    261            par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
    262        }
    263
    264        /**
    265         * Called right before the block is destroyed by a player.  Args: world, x, y, z, metaData
    266         */
    267        public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5)
    268        {
    269            if (this.isRepeaterPowered)
    270            {
    271                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
    272                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
    273                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
    274                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
    275                par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
    276                par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
    277            }
    278
    279            super.onBlockDestroyedByPlayer(par1World, par2, par3, par4, par5);
    280        }
    281
    282        /**
    283         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    284         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    285         */
    286        public boolean isOpaqueCube()
    287        {
    288            return false;
    289        }
    290
    291        /**
    292         * Returns the ID of the items to drop on destruction.
    293         */
    294        public int idDropped(int par1, Random par2Random, int par3)
    295        {
    296            return Item.redstoneRepeater.shiftedIndex;
    297        }
    298
    299        @SideOnly(Side.CLIENT)
    300
    301        /**
    302         * A randomly called display update to be able to add particles or other items for display
    303         */
    304        public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
    305        {
    306            if (this.isRepeaterPowered)
    307            {
    308                int var6 = par1World.getBlockMetadata(par2, par3, par4);
    309                int var7 = getDirection(var6);
    310                double var8 = (double)((float)par2 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    311                double var10 = (double)((float)par3 + 0.4F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    312                double var12 = (double)((float)par4 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    313                double var14 = 0.0D;
    314                double var16 = 0.0D;
    315
    316                if (par5Random.nextInt(2) == 0)
    317                {
    318                    switch (var7)
    319                    {
    320                        case 0:
    321                            var16 = -0.3125D;
    322                            break;
    323                        case 1:
    324                            var14 = 0.3125D;
    325                            break;
    326                        case 2:
    327                            var16 = 0.3125D;
    328                            break;
    329                        case 3:
    330                            var14 = -0.3125D;
    331                    }
    332                }
    333                else
    334                {
    335                    int var18 = (var6 & 12) >> 2;
    336
    337                    switch (var7)
    338                    {
    339                        case 0:
    340                            var16 = repeaterTorchOffset[var18];
    341                            break;
    342                        case 1:
    343                            var14 = -repeaterTorchOffset[var18];
    344                            break;
    345                        case 2:
    346                            var16 = -repeaterTorchOffset[var18];
    347                            break;
    348                        case 3:
    349                            var14 = repeaterTorchOffset[var18];
    350                    }
    351                }
    352
    353                par1World.spawnParticle("reddust", var8 + var14, var10, var12 + var16, 0.0D, 0.0D, 0.0D);
    354            }
    355        }
    356
    357        @SideOnly(Side.CLIENT)
    358
    359        /**
    360         * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
    361         */
    362        public int idPicked(World par1World, int par2, int par3, int par4)
    363        {
    364            return Item.redstoneRepeater.shiftedIndex;
    365        }
    366
    367        public static boolean func_82524_c(int par0)
    368        {
    369            return par0 == Block.redstoneRepeaterActive.blockID || par0 == Block.redstoneRepeaterIdle.blockID;
    370        }
    371    }