    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        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}