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.ignoreTick(par1World, par2, par3, par4, var6);
056    
057            if (this.isRepeaterPowered && !var7)
058            {
059                par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterIdle.blockID, var6);
060            }
061            else if (!this.isRepeaterPowered)
062            {
063                par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterActive.blockID, var6);
064    
065                if (!var7)
066                {
067                    int var8 = (var6 & 12) >> 2;
068                    par1World.scheduleBlockUpdate(par2, par3, par4, Block.redstoneRepeaterActive.blockID, repeaterState[var8] * 2);
069                }
070            }
071        }
072    
073        /**
074         * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
075         */
076        public int getBlockTextureFromSideAndMetadata(int par1, int par2)
077        {
078            return par1 == 0 ? (this.isRepeaterPowered ? 99 : 115) : (par1 == 1 ? (this.isRepeaterPowered ? 147 : 131) : 5);
079        }
080    
081        @SideOnly(Side.CLIENT)
082    
083        /**
084         * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
085         * coordinates.  Args: blockAccess, x, y, z, side
086         */
087        public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
088        {
089            return par5 != 0 && par5 != 1;
090        }
091    
092        /**
093         * The type of render function that is called for this block
094         */
095        public int getRenderType()
096        {
097            return 15;
098        }
099    
100        /**
101         * Returns the block texture based on the side being looked at.  Args: side
102         */
103        public int getBlockTextureFromSide(int par1)
104        {
105            return this.getBlockTextureFromSideAndMetadata(par1, 0);
106        }
107    
108        /**
109         * Is this block indirectly powering the block on the specified side
110         */
111        public boolean isIndirectlyPoweringTo(World par1World, int par2, int par3, int par4, int par5)
112        {
113            return this.isPoweringTo(par1World, par2, par3, par4, par5);
114        }
115    
116        /**
117         * Is this block powering the block on the specified side
118         */
119        public boolean isPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
120        {
121            if (!this.isRepeaterPowered)
122            {
123                return false;
124            }
125            else
126            {
127                int var6 = getDirection(par1IBlockAccess.getBlockMetadata(par2, par3, par4));
128                return var6 == 0 && par5 == 3 ? true : (var6 == 1 && par5 == 4 ? true : (var6 == 2 && par5 == 2 ? true : var6 == 3 && par5 == 5));
129            }
130        }
131    
132        /**
133         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
134         * their own) Args: x, y, z, neighbor blockID
135         */
136        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
137        {
138            if (!this.canBlockStay(par1World, par2, par3, par4))
139            {
140                this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
141                par1World.setBlockWithNotify(par2, par3, par4, 0);
142                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
143                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
144                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
145                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
146                par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
147                par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
148            }
149            else
150            {
151                int var6 = par1World.getBlockMetadata(par2, par3, par4);
152                boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6);
153                int var8 = (var6 & 12) >> 2;
154    
155                if (this.isRepeaterPowered && !var7 || !this.isRepeaterPowered && var7)
156                {
157                    par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, repeaterState[var8] * 2);
158                }
159            }
160        }
161    
162        private boolean ignoreTick(World par1World, int par2, int par3, int par4, int par5)
163        {
164            int var6 = getDirection(par5);
165    
166            switch (var6)
167            {
168                case 0:
169                    return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 + 1, 3) || par1World.getBlockId(par2, par3, par4 + 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 + 1) > 0;
170                case 1:
171                    return par1World.isBlockIndirectlyProvidingPowerTo(par2 - 1, par3, par4, 4) || par1World.getBlockId(par2 - 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 - 1, par3, par4) > 0;
172                case 2:
173                    return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 - 1, 2) || par1World.getBlockId(par2, par3, par4 - 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 - 1) > 0;
174                case 3:
175                    return par1World.isBlockIndirectlyProvidingPowerTo(par2 + 1, par3, par4, 5) || par1World.getBlockId(par2 + 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 + 1, par3, par4) > 0;
176                default:
177                    return false;
178            }
179        }
180    
181        /**
182         * Called upon block activation (right click on the block.)
183         */
184        public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
185        {
186            int var10 = par1World.getBlockMetadata(par2, par3, par4);
187            int var11 = (var10 & 12) >> 2;
188            var11 = var11 + 1 << 2 & 12;
189            par1World.setBlockMetadataWithNotify(par2, par3, par4, var11 | var10 & 3);
190            return true;
191        }
192    
193        /**
194         * Can this block provide power. Only wire currently seems to have this change based on its state.
195         */
196        public boolean canProvidePower()
197        {
198            return true;
199        }
200    
201        /**
202         * Called when the block is placed in the world.
203         */
204        public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving)
205        {
206            int var6 = ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4;
207            par1World.setBlockMetadataWithNotify(par2, par3, par4, var6);
208            boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6);
209    
210            if (var7)
211            {
212                par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, 1);
213            }
214        }
215    
216        /**
217         * Called whenever the block is added into the world. Args: world, x, y, z
218         */
219        public void onBlockAdded(World par1World, int par2, int par3, int par4)
220        {
221            par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
222            par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
223            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
224            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
225            par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
226            par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
227        }
228    
229        /**
230         * Called right before the block is destroyed by a player.  Args: world, x, y, z, metaData
231         */
232        public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5)
233        {
234            if (this.isRepeaterPowered)
235            {
236                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
237                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
238                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
239                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
240                par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
241                par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
242            }
243    
244            super.onBlockDestroyedByPlayer(par1World, par2, par3, par4, par5);
245        }
246    
247        /**
248         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
249         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
250         */
251        public boolean isOpaqueCube()
252        {
253            return false;
254        }
255    
256        /**
257         * Returns the ID of the items to drop on destruction.
258         */
259        public int idDropped(int par1, Random par2Random, int par3)
260        {
261            return Item.redstoneRepeater.shiftedIndex;
262        }
263    
264        @SideOnly(Side.CLIENT)
265    
266        /**
267         * A randomly called display update to be able to add particles or other items for display
268         */
269        public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
270        {
271            if (this.isRepeaterPowered)
272            {
273                int var6 = par1World.getBlockMetadata(par2, par3, par4);
274                int var7 = getDirection(var6);
275                double var8 = (double)((float)par2 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
276                double var10 = (double)((float)par3 + 0.4F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
277                double var12 = (double)((float)par4 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
278                double var14 = 0.0D;
279                double var16 = 0.0D;
280    
281                if (par5Random.nextInt(2) == 0)
282                {
283                    switch (var7)
284                    {
285                        case 0:
286                            var16 = -0.3125D;
287                            break;
288                        case 1:
289                            var14 = 0.3125D;
290                            break;
291                        case 2:
292                            var16 = 0.3125D;
293                            break;
294                        case 3:
295                            var14 = -0.3125D;
296                    }
297                }
298                else
299                {
300                    int var18 = (var6 & 12) >> 2;
301    
302                    switch (var7)
303                    {
304                        case 0:
305                            var16 = repeaterTorchOffset[var18];
306                            break;
307                        case 1:
308                            var14 = -repeaterTorchOffset[var18];
309                            break;
310                        case 2:
311                            var16 = -repeaterTorchOffset[var18];
312                            break;
313                        case 3:
314                            var14 = repeaterTorchOffset[var18];
315                    }
316                }
317    
318                par1World.spawnParticle("reddust", var8 + var14, var10, var12 + var16, 0.0D, 0.0D, 0.0D);
319            }
320        }
321    
322        @SideOnly(Side.CLIENT)
323    
324        /**
325         * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
326         */
327        public int idPicked(World par1World, int par2, int par3, int par4)
328        {
329            return Item.redstoneRepeater.shiftedIndex;
330        }
331    }