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