001package net.minecraft.block;
002
003import net.minecraft.block.material.Material;
004import net.minecraft.creativetab.CreativeTabs;
005import net.minecraft.entity.EntityLiving;
006import net.minecraft.entity.player.EntityPlayer;
007import net.minecraft.item.ItemStack;
008import net.minecraft.util.AxisAlignedBB;
009import net.minecraft.util.MathHelper;
010import net.minecraft.world.IBlockAccess;
011import net.minecraft.world.World;
012
013import net.minecraftforge.common.ForgeDirection;
014import static net.minecraftforge.common.ForgeDirection.*;
015
016public class BlockLever extends Block
017{
018    protected BlockLever(int par1)
019    {
020        super(par1, Material.circuits);
021        this.setCreativeTab(CreativeTabs.tabRedstone);
022    }
023
024    /**
025     * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
026     * cleared to be reused)
027     */
028    public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
029    {
030        return null;
031    }
032
033    /**
034     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
035     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
036     */
037    public boolean isOpaqueCube()
038    {
039        return false;
040    }
041
042    /**
043     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
044     */
045    public boolean renderAsNormalBlock()
046    {
047        return false;
048    }
049
050    /**
051     * The type of render function that is called for this block
052     */
053    public int getRenderType()
054    {
055        return 12;
056    }
057
058    /**
059     * checks to see if you can place this block can be placed on that side of a block: BlockLever overrides
060     */
061    public boolean canPlaceBlockOnSide(World par1World, int par2, int par3, int par4, int par5)
062    {
063        ForgeDirection dir = ForgeDirection.getOrientation(par5);
064        return (dir == DOWN  && par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN )) ||
065               (dir == UP    && par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP   )) ||
066               (dir == NORTH && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH)) ||
067               (dir == SOUTH && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH)) ||
068               (dir == WEST  && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST )) ||
069               (dir == EAST  && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST ));
070    }
071
072    /**
073     * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
074     */
075    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
076    {
077        return par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST ) ||
078               par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST ) ||
079               par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH) ||
080               par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH) ||
081               par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP   ) ||
082               par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN );
083    }
084
085    /**
086     * Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata
087     */
088    public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9)
089    {
090        int j1 = par9 & 8;
091        int k1 = par9 & 7;
092        byte b0 = -1;
093
094        if (par5 == 0 && par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN))
095        {
096            b0 = 0;
097        }
098
099        if (par5 == 1 && par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP))
100        {
101            b0 = 5;
102        }
103
104        if (par5 == 2 && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH))
105        {
106            b0 = 4;
107        }
108
109        if (par5 == 3 && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH))
110        {
111            b0 = 3;
112        }
113
114        if (par5 == 4 && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST))
115        {
116            b0 = 2;
117        }
118
119        if (par5 == 5 && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST))
120        {
121            b0 = 1;
122        }
123
124        return b0 + j1;
125    }
126
127    /**
128     * Called when the block is placed in the world.
129     */
130    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack)
131    {
132        int l = par1World.getBlockMetadata(par2, par3, par4);
133        int i1 = l & 7;
134        int j1 = l & 8;
135
136        if (i1 == invertMetadata(1))
137        {
138            if ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 1) == 0)
139            {
140                par1World.setBlockMetadataWithNotify(par2, par3, par4, 5 | j1, 2);
141            }
142            else
143            {
144                par1World.setBlockMetadataWithNotify(par2, par3, par4, 6 | j1, 2);
145            }
146        }
147        else if (i1 == invertMetadata(0))
148        {
149            if ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 1) == 0)
150            {
151                par1World.setBlockMetadataWithNotify(par2, par3, par4, 7 | j1, 2);
152            }
153            else
154            {
155                par1World.setBlockMetadataWithNotify(par2, par3, par4, 0 | j1, 2);
156            }
157        }
158    }
159
160    /**
161     * only used in ComponentScatteredFeatureJunglePyramid.addComponentParts"
162     */
163    public static int invertMetadata(int par0)
164    {
165        switch (par0)
166        {
167            case 0:
168                return 0;
169            case 1:
170                return 5;
171            case 2:
172                return 4;
173            case 3:
174                return 3;
175            case 4:
176                return 2;
177            case 5:
178                return 1;
179            default:
180                return -1;
181        }
182    }
183
184    /**
185     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
186     * their own) Args: x, y, z, neighbor blockID
187     */
188    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
189    {
190        if (this.checkIfAttachedToBlock(par1World, par2, par3, par4))
191        {
192            int i1 = par1World.getBlockMetadata(par2, par3, par4) & 7;
193            boolean flag = false;
194
195            if (!par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST) && i1 == 1)
196            {
197                flag = true;
198            }
199
200            if (!par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST) && i1 == 2)
201            {
202                flag = true;
203            }
204
205            if (!par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH) && i1 == 3)
206            {
207                flag = true;
208            }
209
210            if (!par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH) && i1 == 4)
211            {
212                flag = true;
213            }
214
215            if (!par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP) && i1 == 5)
216            {
217                flag = true;
218            }
219
220            if (!par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP) && i1 == 6)
221            {
222                flag = true;
223            }
224
225            if (!par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN) && i1 == 0)
226            {
227                flag = true;
228            }
229
230            if (!par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN) && i1 == 7)
231            {
232                flag = true;
233            }
234
235            if (flag)
236            {
237                this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
238                par1World.func_94571_i(par2, par3, par4);
239            }
240        }
241    }
242
243    /**
244     * Checks if the block is attached to another block. If it is not, it returns false and drops the block as an item.
245     * If it is it returns true.
246     */
247    private boolean checkIfAttachedToBlock(World par1World, int par2, int par3, int par4)
248    {
249        if (!this.canPlaceBlockAt(par1World, par2, par3, par4))
250        {
251            this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
252            par1World.func_94571_i(par2, par3, par4);
253            return false;
254        }
255        else
256        {
257            return true;
258        }
259    }
260
261    /**
262     * Updates the blocks bounds based on its current state. Args: world, x, y, z
263     */
264    public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
265    {
266        int l = par1IBlockAccess.getBlockMetadata(par2, par3, par4) & 7;
267        float f = 0.1875F;
268
269        if (l == 1)
270        {
271            this.setBlockBounds(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f);
272        }
273        else if (l == 2)
274        {
275            this.setBlockBounds(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f);
276        }
277        else if (l == 3)
278        {
279            this.setBlockBounds(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F);
280        }
281        else if (l == 4)
282        {
283            this.setBlockBounds(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F);
284        }
285        else if (l != 5 && l != 6)
286        {
287            if (l == 0 || l == 7)
288            {
289                f = 0.25F;
290                this.setBlockBounds(0.5F - f, 0.4F, 0.5F - f, 0.5F + f, 1.0F, 0.5F + f);
291            }
292        }
293        else
294        {
295            f = 0.25F;
296            this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.6F, 0.5F + f);
297        }
298    }
299
300    /**
301     * Called upon block activation (right click on the block.)
302     */
303    public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
304    {
305        if (par1World.isRemote)
306        {
307            return true;
308        }
309        else
310        {
311            int i1 = par1World.getBlockMetadata(par2, par3, par4);
312            int j1 = i1 & 7;
313            int k1 = 8 - (i1 & 8);
314            par1World.setBlockMetadataWithNotify(par2, par3, par4, j1 + k1, 3);
315            par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.5D, (double)par4 + 0.5D, "random.click", 0.3F, k1 > 0 ? 0.6F : 0.5F);
316            par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID);
317
318            if (j1 == 1)
319            {
320                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
321            }
322            else if (j1 == 2)
323            {
324                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
325            }
326            else if (j1 == 3)
327            {
328                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
329            }
330            else if (j1 == 4)
331            {
332                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
333            }
334            else if (j1 != 5 && j1 != 6)
335            {
336                if (j1 == 0 || j1 == 7)
337                {
338                    par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
339                }
340            }
341            else
342            {
343                par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
344            }
345
346            return true;
347        }
348    }
349
350    /**
351     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
352     */
353    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
354    {
355        if ((par6 & 8) > 0)
356        {
357            par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID);
358            int j1 = par6 & 7;
359
360            if (j1 == 1)
361            {
362                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
363            }
364            else if (j1 == 2)
365            {
366                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
367            }
368            else if (j1 == 3)
369            {
370                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
371            }
372            else if (j1 == 4)
373            {
374                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
375            }
376            else if (j1 != 5 && j1 != 6)
377            {
378                if (j1 == 0 || j1 == 7)
379                {
380                    par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
381                }
382            }
383            else
384            {
385                par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
386            }
387        }
388
389        super.breakBlock(par1World, par2, par3, par4, par5, par6);
390    }
391
392    /**
393     * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube
394     * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X,
395     * Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
396     */
397    public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
398    {
399        return (par1IBlockAccess.getBlockMetadata(par2, par3, par4) & 8) > 0 ? 15 : 0;
400    }
401
402    /**
403     * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z,
404     * side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
405     */
406    public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
407    {
408        int i1 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
409
410        if ((i1 & 8) == 0)
411        {
412            return 0;
413        }
414        else
415        {
416            int j1 = i1 & 7;
417            return j1 == 0 && par5 == 0 ? 15 : (j1 == 7 && par5 == 0 ? 15 : (j1 == 6 && par5 == 1 ? 15 : (j1 == 5 && par5 == 1 ? 15 : (j1 == 4 && par5 == 2 ? 15 : (j1 == 3 && par5 == 3 ? 15 : (j1 == 2 && par5 == 4 ? 15 : (j1 == 1 && par5 == 5 ? 15 : 0)))))));
418        }
419    }
420
421    /**
422     * Can this block provide power. Only wire currently seems to have this change based on its state.
423     */
424    public boolean canProvidePower()
425    {
426        return true;
427    }
428}