    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}