001    package net.minecraft.src;
002    
003    import java.util.List;
004    import java.util.Random;
005    
006    import net.minecraftforge.common.ForgeDirection;
007    
008    import static net.minecraftforge.common.ForgeDirection.*;
009    
010    public class BlockButton extends Block
011    {
012        /** Whether this button is sensible to arrows, used by wooden buttons. */
013        private final boolean sensible;
014    
015        protected BlockButton(int par1, int par2, boolean par3)
016        {
017            super(par1, par2, Material.circuits);
018            this.setTickRandomly(true);
019            this.setCreativeTab(CreativeTabs.tabRedstone);
020            this.sensible = par3;
021        }
022    
023        /**
024         * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
025         * cleared to be reused)
026         */
027        public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
028        {
029            return null;
030        }
031    
032        /**
033         * How many world ticks before ticking
034         */
035        public int tickRate()
036        {
037            return this.sensible ? 30 : 20;
038        }
039    
040        /**
041         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
042         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
043         */
044        public boolean isOpaqueCube()
045        {
046            return false;
047        }
048    
049        /**
050         * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
051         */
052        public boolean renderAsNormalBlock()
053        {
054            return false;
055        }
056    
057        /**
058         * checks to see if you can place this block can be placed on that side of a block: BlockLever overrides
059         */
060        public boolean canPlaceBlockOnSide(World par1World, int par2, int par3, int par4, int par5)
061        {
062            ForgeDirection dir = ForgeDirection.getOrientation(par5);
063            return (dir == NORTH && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH)) ||
064                   (dir == SOUTH && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH)) ||
065                   (dir == WEST  && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST)) ||
066                   (dir == EAST  && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST));
067        }
068    
069        /**
070         * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
071         */
072        public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
073        {
074            return (par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST)) ||
075                   (par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST)) ||
076                   (par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH)) ||
077                   (par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH));
078        }
079    
080        /**
081         * called before onBlockPlacedBy by ItemBlock and ItemReed
082         */
083        public void updateBlockMetadata(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8)
084        {
085            int var9 = par1World.getBlockMetadata(par2, par3, par4);
086            int var10 = var9 & 8;
087            var9 &= 7;
088            
089            ForgeDirection dir = ForgeDirection.getOrientation(par5);
090    
091            if (dir == NORTH && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH))
092            {
093                var9 = 4;
094            }
095            else if (dir == SOUTH && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH))
096            {
097                var9 = 3;
098            }
099            else if (dir == WEST && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST))
100            {
101                var9 = 2;
102            }
103            else if (dir == EAST && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST))
104            {
105                var9 = 1;
106            }
107            else
108            {
109                var9 = this.getOrientation(par1World, par2, par3, par4);
110            }
111    
112            par1World.setBlockMetadataWithNotify(par2, par3, par4, var9 + var10);
113        }
114    
115        /**
116         * Get side which this button is facing.
117         */
118        private int getOrientation(World par1World, int par2, int par3, int par4)
119        {
120            if (par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST)) return 1; 
121            if (par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST)) return 2; 
122            if (par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH)) return 3; 
123            if (par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH)) return 4;
124            return 1;
125        }
126    
127        /**
128         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
129         * their own) Args: x, y, z, neighbor blockID
130         */
131        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
132        {
133            if (this.redundantCanPlaceBlockAt(par1World, par2, par3, par4))
134            {
135                int var6 = par1World.getBlockMetadata(par2, par3, par4) & 7;
136                boolean var7 = false;
137    
138                if (!par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST) && var6 == 1)
139                {
140                    var7 = true;
141                }
142    
143                if (!par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST) && var6 == 2)
144                {
145                    var7 = true;
146                }
147    
148                if (!par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH) && var6 == 3)
149                {
150                    var7 = true;
151                }
152    
153                if (!par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH) && var6 == 4)
154                {
155                    var7 = true;
156                }
157    
158                if (var7)
159                {
160                    this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
161                    par1World.setBlockWithNotify(par2, par3, par4, 0);
162                }
163            }
164        }
165    
166        /**
167         * This method is redundant, check it out...
168         */
169        private boolean redundantCanPlaceBlockAt(World par1World, int par2, int par3, int par4)
170        {
171            if (!this.canPlaceBlockAt(par1World, par2, par3, par4))
172            {
173                this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
174                par1World.setBlockWithNotify(par2, par3, par4, 0);
175                return false;
176            }
177            else
178            {
179                return true;
180            }
181        }
182    
183        /**
184         * Updates the blocks bounds based on its current state. Args: world, x, y, z
185         */
186        public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
187        {
188            int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
189            this.func_82534_e(var5);
190        }
191    
192        private void func_82534_e(int par1)
193        {
194            int var2 = par1 & 7;
195            boolean var3 = (par1 & 8) > 0;
196            float var4 = 0.375F;
197            float var5 = 0.625F;
198            float var6 = 0.1875F;
199            float var7 = 0.125F;
200    
201            if (var3)
202            {
203                var7 = 0.0625F;
204            }
205    
206            if (var2 == 1)
207            {
208                this.setBlockBounds(0.0F, var4, 0.5F - var6, var7, var5, 0.5F + var6);
209            }
210            else if (var2 == 2)
211            {
212                this.setBlockBounds(1.0F - var7, var4, 0.5F - var6, 1.0F, var5, 0.5F + var6);
213            }
214            else if (var2 == 3)
215            {
216                this.setBlockBounds(0.5F - var6, var4, 0.0F, 0.5F + var6, var5, var7);
217            }
218            else if (var2 == 4)
219            {
220                this.setBlockBounds(0.5F - var6, var4, 1.0F - var7, 0.5F + var6, var5, 1.0F);
221            }
222        }
223    
224        /**
225         * Called when the block is clicked by a player. Args: x, y, z, entityPlayer
226         */
227        public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer) {}
228    
229        /**
230         * Called upon block activation (right click on the block.)
231         */
232        public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
233        {
234            int var10 = par1World.getBlockMetadata(par2, par3, par4);
235            int var11 = var10 & 7;
236            int var12 = 8 - (var10 & 8);
237    
238            if (var12 == 0)
239            {
240                return true;
241            }
242            else
243            {
244                par1World.setBlockMetadataWithNotify(par2, par3, par4, var11 + var12);
245                par1World.markBlocksDirty(par2, par3, par4, par2, par3, par4);
246                par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.5D, (double)par4 + 0.5D, "random.click", 0.3F, 0.6F);
247                this.func_82536_d(par1World, par2, par3, par4, var11);
248                par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate());
249                return true;
250            }
251        }
252    
253        /**
254         * ejects contained items into the world, and notifies neighbours of an update, as appropriate
255         */
256        public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
257        {
258            if ((par6 & 8) > 0)
259            {
260                int var7 = par6 & 7;
261                this.func_82536_d(par1World, par2, par3, par4, var7);
262            }
263    
264            super.breakBlock(par1World, par2, par3, par4, par5, par6);
265        }
266    
267        /**
268         * Is this block powering the block on the specified side
269         */
270        public boolean isPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
271        {
272            return (par1IBlockAccess.getBlockMetadata(par2, par3, par4) & 8) > 0;
273        }
274    
275        /**
276         * Is this block indirectly powering the block on the specified side
277         */
278        public boolean isIndirectlyPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
279        {
280            int var6 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
281    
282            if ((var6 & 8) == 0)
283            {
284                return false;
285            }
286            else
287            {
288                int var7 = var6 & 7;
289                return var7 == 5 && par5 == 1 ? true : (var7 == 4 && par5 == 2 ? true : (var7 == 3 && par5 == 3 ? true : (var7 == 2 && par5 == 4 ? true : var7 == 1 && par5 == 5)));
290            }
291        }
292    
293        /**
294         * Can this block provide power. Only wire currently seems to have this change based on its state.
295         */
296        public boolean canProvidePower()
297        {
298            return true;
299        }
300    
301        /**
302         * Ticks the block if it's been scheduled
303         */
304        public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
305        {
306            if (!par1World.isRemote)
307            {
308                int var6 = par1World.getBlockMetadata(par2, par3, par4);
309    
310                if ((var6 & 8) != 0)
311                {
312                    if (this.sensible)
313                    {
314                        this.func_82535_o(par1World, par2, par3, par4);
315                    }
316                    else
317                    {
318                        par1World.setBlockMetadataWithNotify(par2, par3, par4, var6 & 7);
319                        int var7 = var6 & 7;
320                        this.func_82536_d(par1World, par2, par3, par4, var7);
321                        par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.5D, (double)par4 + 0.5D, "random.click", 0.3F, 0.5F);
322                        par1World.markBlocksDirty(par2, par3, par4, par2, par3, par4);
323                    }
324                }
325            }
326        }
327    
328        /**
329         * Sets the block's bounds for rendering it as an item
330         */
331        public void setBlockBoundsForItemRender()
332        {
333            float var1 = 0.1875F;
334            float var2 = 0.125F;
335            float var3 = 0.125F;
336            this.setBlockBounds(0.5F - var1, 0.5F - var2, 0.5F - var3, 0.5F + var1, 0.5F + var2, 0.5F + var3);
337        }
338    
339        /**
340         * Triggered whenever an entity collides with this block (enters into the block). Args: world, x, y, z, entity
341         */
342        public void onEntityCollidedWithBlock(World par1World, int par2, int par3, int par4, Entity par5Entity)
343        {
344            if (!par1World.isRemote)
345            {
346                if (this.sensible)
347                {
348                    if ((par1World.getBlockMetadata(par2, par3, par4) & 8) == 0)
349                    {
350                        this.func_82535_o(par1World, par2, par3, par4);
351                    }
352                }
353            }
354        }
355    
356        private void func_82535_o(World par1World, int par2, int par3, int par4)
357        {
358            int var5 = par1World.getBlockMetadata(par2, par3, par4);
359            int var6 = var5 & 7;
360            boolean var7 = (var5 & 8) != 0;
361            this.func_82534_e(var5);
362            List var9 = par1World.getEntitiesWithinAABB(EntityArrow.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)par2 + this.minX, (double)par3 + this.minY, (double)par4 + this.minZ, (double)par2 + this.maxX, (double)par3 + this.maxY, (double)par4 + this.maxZ));
363            boolean var8 = !var9.isEmpty();
364    
365            if (var8 && !var7)
366            {
367                par1World.setBlockMetadataWithNotify(par2, par3, par4, var6 | 8);
368                this.func_82536_d(par1World, par2, par3, par4, var6);
369                par1World.markBlocksDirty(par2, par3, par4, par2, par3, par4);
370                par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.5D, (double)par4 + 0.5D, "random.click", 0.3F, 0.6F);
371            }
372    
373            if (!var8 && var7)
374            {
375                par1World.setBlockMetadataWithNotify(par2, par3, par4, var6);
376                this.func_82536_d(par1World, par2, par3, par4, var6);
377                par1World.markBlocksDirty(par2, par3, par4, par2, par3, par4);
378                par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.5D, (double)par4 + 0.5D, "random.click", 0.3F, 0.5F);
379            }
380    
381            if (var8)
382            {
383                par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate());
384            }
385        }
386    
387        private void func_82536_d(World par1World, int par2, int par3, int par4, int par5)
388        {
389            par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID);
390    
391            if (par5 == 1)
392            {
393                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
394            }
395            else if (par5 == 2)
396            {
397                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
398            }
399            else if (par5 == 3)
400            {
401                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
402            }
403            else if (par5 == 4)
404            {
405                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
406            }
407            else
408            {
409                par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
410            }
411        }
412    }