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