001    package net.minecraft.block;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.SideOnly;
005    import net.minecraft.block.material.Material;
006    import net.minecraft.creativetab.CreativeTabs;
007    import net.minecraft.entity.player.EntityPlayer;
008    import net.minecraft.util.AxisAlignedBB;
009    import net.minecraft.util.MovingObjectPosition;
010    import net.minecraft.util.Vec3;
011    import net.minecraft.world.IBlockAccess;
012    import net.minecraft.world.World;
013    
014    import net.minecraftforge.common.ForgeDirection;
015    
016    public class BlockTrapDoor extends Block
017    {
018        /** Set this to allow trapdoors to remain free-floating */
019        public static boolean disableValidation = false;
020    
021        protected BlockTrapDoor(int par1, Material par2Material)
022        {
023            super(par1, par2Material);
024            this.blockIndexInTexture = 84;
025    
026            if (par2Material == Material.iron)
027            {
028                ++this.blockIndexInTexture;
029            }
030    
031            float var3 = 0.5F;
032            float var4 = 1.0F;
033            this.setBlockBounds(0.5F - var3, 0.0F, 0.5F - var3, 0.5F + var3, var4, 0.5F + var3);
034            this.setCreativeTab(CreativeTabs.tabRedstone);
035        }
036    
037        /**
038         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
039         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
040         */
041        public boolean isOpaqueCube()
042        {
043            return false;
044        }
045    
046        /**
047         * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
048         */
049        public boolean renderAsNormalBlock()
050        {
051            return false;
052        }
053    
054        public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
055        {
056            return !isTrapdoorOpen(par1IBlockAccess.getBlockMetadata(par2, par3, par4));
057        }
058    
059        /**
060         * The type of render function that is called for this block
061         */
062        public int getRenderType()
063        {
064            return 0;
065        }
066    
067        @SideOnly(Side.CLIENT)
068    
069        /**
070         * Returns the bounding box of the wired rectangular prism to render.
071         */
072        public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
073        {
074            this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
075            return super.getSelectedBoundingBoxFromPool(par1World, par2, par3, par4);
076        }
077    
078        /**
079         * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
080         * cleared to be reused)
081         */
082        public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
083        {
084            this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
085            return super.getCollisionBoundingBoxFromPool(par1World, par2, par3, par4);
086        }
087    
088        /**
089         * Updates the blocks bounds based on its current state. Args: world, x, y, z
090         */
091        public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
092        {
093            this.setBlockBoundsForBlockRender(par1IBlockAccess.getBlockMetadata(par2, par3, par4));
094        }
095    
096        /**
097         * Sets the block's bounds for rendering it as an item
098         */
099        public void setBlockBoundsForItemRender()
100        {
101            float var1 = 0.1875F;
102            this.setBlockBounds(0.0F, 0.5F - var1 / 2.0F, 0.0F, 1.0F, 0.5F + var1 / 2.0F, 1.0F);
103        }
104    
105        public void setBlockBoundsForBlockRender(int par1)
106        {
107            float var2 = 0.1875F;
108    
109            if ((par1 & 8) != 0)
110            {
111                this.setBlockBounds(0.0F, 1.0F - var2, 0.0F, 1.0F, 1.0F, 1.0F);
112            }
113            else
114            {
115                this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, var2, 1.0F);
116            }
117    
118            if (isTrapdoorOpen(par1))
119            {
120                if ((par1 & 3) == 0)
121                {
122                    this.setBlockBounds(0.0F, 0.0F, 1.0F - var2, 1.0F, 1.0F, 1.0F);
123                }
124    
125                if ((par1 & 3) == 1)
126                {
127                    this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, var2);
128                }
129    
130                if ((par1 & 3) == 2)
131                {
132                    this.setBlockBounds(1.0F - var2, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
133                }
134    
135                if ((par1 & 3) == 3)
136                {
137                    this.setBlockBounds(0.0F, 0.0F, 0.0F, var2, 1.0F, 1.0F);
138                }
139            }
140        }
141    
142        /**
143         * Called when the block is clicked by a player. Args: x, y, z, entityPlayer
144         */
145        public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer) {}
146    
147        /**
148         * Called upon block activation (right click on the block.)
149         */
150        public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
151        {
152            if (this.blockMaterial == Material.iron)
153            {
154                return true;
155            }
156            else
157            {
158                int var10 = par1World.getBlockMetadata(par2, par3, par4);
159                par1World.setBlockMetadataWithNotify(par2, par3, par4, var10 ^ 4);
160                par1World.playAuxSFXAtEntity(par5EntityPlayer, 1003, par2, par3, par4, 0);
161                return true;
162            }
163        }
164    
165        public void onPoweredBlockChange(World par1World, int par2, int par3, int par4, boolean par5)
166        {
167            int var6 = par1World.getBlockMetadata(par2, par3, par4);
168            boolean var7 = (var6 & 4) > 0;
169    
170            if (var7 != par5)
171            {
172                par1World.setBlockMetadataWithNotify(par2, par3, par4, var6 ^ 4);
173                par1World.playAuxSFXAtEntity((EntityPlayer)null, 1003, par2, par3, par4, 0);
174            }
175        }
176    
177        /**
178         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
179         * their own) Args: x, y, z, neighbor blockID
180         */
181        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
182        {
183            if (!par1World.isRemote)
184            {
185                int var6 = par1World.getBlockMetadata(par2, par3, par4);
186                int var7 = par2;
187                int var8 = par4;
188    
189                if ((var6 & 3) == 0)
190                {
191                    var8 = par4 + 1;
192                }
193    
194                if ((var6 & 3) == 1)
195                {
196                    --var8;
197                }
198    
199                if ((var6 & 3) == 2)
200                {
201                    var7 = par2 + 1;
202                }
203    
204                if ((var6 & 3) == 3)
205                {
206                    --var7;
207                }
208    
209                if (!(isValidSupportBlock(par1World.getBlockId(var7, par3, var8)) || par1World.isBlockSolidOnSide(var7, par3, var8, ForgeDirection.getOrientation((var6 & 3) + 2))))
210                {
211                    par1World.setBlockWithNotify(par2, par3, par4, 0);
212                    this.dropBlockAsItem(par1World, par2, par3, par4, var6, 0);
213                }
214    
215                boolean var9 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4);
216    
217                if (var9 || par5 > 0 && Block.blocksList[par5].canProvidePower())
218                {
219                    this.onPoweredBlockChange(par1World, par2, par3, par4, var9);
220                }
221            }
222        }
223    
224        /**
225         * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world,
226         * x, y, z, startVec, endVec
227         */
228        public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3)
229        {
230            this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
231            return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3);
232        }
233    
234        /**
235         * Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata
236         */
237        public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9)
238        {
239            int var10 = 0;
240    
241            if (par5 == 2)
242            {
243                var10 = 0;
244            }
245    
246            if (par5 == 3)
247            {
248                var10 = 1;
249            }
250    
251            if (par5 == 4)
252            {
253                var10 = 2;
254            }
255    
256            if (par5 == 5)
257            {
258                var10 = 3;
259            }
260    
261            if (par5 != 1 && par5 != 0 && par7 > 0.5F)
262            {
263                var10 |= 8;
264            }
265    
266            return var10;
267        }
268    
269        /**
270         * checks to see if you can place this block can be placed on that side of a block: BlockLever overrides
271         */
272        public boolean canPlaceBlockOnSide(World par1World, int par2, int par3, int par4, int par5)
273        {
274            if (disableValidation)
275            {
276                return true;
277            }
278            if (par5 == 0)
279            {
280                return false;
281            }
282            else if (par5 == 1)
283            {
284                return false;
285            }
286            else
287            {
288                if (par5 == 2)
289                {
290                    ++par4;
291                }
292    
293                if (par5 == 3)
294                {
295                    --par4;
296                }
297    
298                if (par5 == 4)
299                {
300                    ++par2;
301                }
302    
303                if (par5 == 5)
304                {
305                    --par2;
306                }
307    
308                return isValidSupportBlock(par1World.getBlockId(par2, par3, par4)) || par1World.isBlockSolidOnSide(par2, par3, par4, ForgeDirection.UP);
309            }
310        }
311    
312        public static boolean isTrapdoorOpen(int par0)
313        {
314            return (par0 & 4) != 0;
315        }
316    
317        /**
318         * Checks if the block ID is a valid support block for the trap door to connect with. If it is not the trapdoor is
319         * dropped into the world.
320         */
321        private static boolean isValidSupportBlock(int par0)
322        {
323            if (disableValidation)
324            {
325                return true;
326            }
327            if (par0 <= 0)
328            {
329                return false;
330            }
331            else
332            {
333                Block var1 = Block.blocksList[par0];
334                return var1 != null && var1.blockMaterial.isOpaque() && var1.renderAsNormalBlock() || var1 == Block.glowStone || var1 instanceof BlockHalfSlab || var1 instanceof BlockStairs;
335            }
336        }
337    }