    001package net.minecraft.block;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.Random;
    006import net.minecraft.block.material.Material;
    007import net.minecraft.client.renderer.IconFlipped;
    008import net.minecraft.client.renderer.texture.IconRegister;
    009import net.minecraft.entity.player.EntityPlayer;
    010import net.minecraft.item.Item;
    011import net.minecraft.util.AxisAlignedBB;
    012import net.minecraft.util.Icon;
    013import net.minecraft.util.MovingObjectPosition;
    014import net.minecraft.util.Vec3;
    015import net.minecraft.world.IBlockAccess;
    016import net.minecraft.world.World;
    017
    018public class BlockDoor extends Block
    019{
    020    private static final String[] doorIconNames = new String[] {"doorWood_lower", "doorWood_upper", "doorIron_lower", "doorIron_upper"};
    021
    022    /** Used for pointing at icon names. */
    023    private final int doorTypeForIcon;
    024    @SideOnly(Side.CLIENT)
    025    private Icon[] iconArray;
    026
    027    protected BlockDoor(int par1, Material par2Material)
    028    {
    029        super(par1, par2Material);
    030
    031        if (par2Material == Material.iron)
    032        {
    033            this.doorTypeForIcon = 2;
    034        }
    035        else
    036        {
    037            this.doorTypeForIcon = 0;
    038        }
    039
    040        float f = 0.5F;
    041        float f1 = 1.0F;
    042        this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f);
    043    }
    044
    045    @SideOnly(Side.CLIENT)
    046
    047    /**
    048     * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
    049     */
    050    public Icon getIcon(int par1, int par2)
    051    {
    052        return this.iconArray[this.doorTypeForIcon];
    053    }
    054
    055    @SideOnly(Side.CLIENT)
    056
    057    /**
    058     * Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side
    059     */
    060    public Icon getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    061    {
    062        if (par5 != 1 && par5 != 0)
    063        {
    064            int i1 = this.getFullMetadata(par1IBlockAccess, par2, par3, par4);
    065            int j1 = i1 & 3;
    066            boolean flag = (i1 & 4) != 0;
    067            boolean flag1 = false;
    068            boolean flag2 = (i1 & 8) != 0;
    069
    070            if (flag)
    071            {
    072                if (j1 == 0 && par5 == 2)
    073                {
    074                    flag1 = !flag1;
    075                }
    076                else if (j1 == 1 && par5 == 5)
    077                {
    078                    flag1 = !flag1;
    079                }
    080                else if (j1 == 2 && par5 == 3)
    081                {
    082                    flag1 = !flag1;
    083                }
    084                else if (j1 == 3 && par5 == 4)
    085                {
    086                    flag1 = !flag1;
    087                }
    088            }
    089            else
    090            {
    091                if (j1 == 0 && par5 == 5)
    092                {
    093                    flag1 = !flag1;
    094                }
    095                else if (j1 == 1 && par5 == 3)
    096                {
    097                    flag1 = !flag1;
    098                }
    099                else if (j1 == 2 && par5 == 4)
    100                {
    101                    flag1 = !flag1;
    102                }
    103                else if (j1 == 3 && par5 == 2)
    104                {
    105                    flag1 = !flag1;
    106                }
    107
    108                if ((i1 & 16) != 0)
    109                {
    110                    flag1 = !flag1;
    111                }
    112            }
    113
    114            return this.iconArray[this.doorTypeForIcon + (flag1 ? doorIconNames.length : 0) + (flag2 ? 1 : 0)];
    115        }
    116        else
    117        {
    118            return this.iconArray[this.doorTypeForIcon];
    119        }
    120    }
    121
    122    @SideOnly(Side.CLIENT)
    123
    124    /**
    125     * When this method is called, your block should register all the icons it needs with the given IconRegister. This
    126     * is the only chance you get to register icons.
    127     */
    128    public void registerIcons(IconRegister par1IconRegister)
    129    {
    130        this.iconArray = new Icon[doorIconNames.length * 2];
    131
    132        for (int i = 0; i < doorIconNames.length; ++i)
    133        {
    134            this.iconArray[i] = par1IconRegister.registerIcon(doorIconNames[i]);
    135            this.iconArray[i + doorIconNames.length] = new IconFlipped(this.iconArray[i], true, false);
    136        }
    137    }
    138
    139    /**
    140     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    141     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    142     */
    143    public boolean isOpaqueCube()
    144    {
    145        return false;
    146    }
    147
    148    public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    149    {
    150        int l = this.getFullMetadata(par1IBlockAccess, par2, par3, par4);
    151        return (l & 4) != 0;
    152    }
    153
    154    /**
    155     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
    156     */
    157    public boolean renderAsNormalBlock()
    158    {
    159        return false;
    160    }
    161
    162    /**
    163     * The type of render function that is called for this block
    164     */
    165    public int getRenderType()
    166    {
    167        return 7;
    168    }
    169
    170    @SideOnly(Side.CLIENT)
    171
    172    /**
    173     * Returns the bounding box of the wired rectangular prism to render.
    174     */
    175    public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
    176    {
    177        this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
    178        return super.getSelectedBoundingBoxFromPool(par1World, par2, par3, par4);
    179    }
    180
    181    /**
    182     * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
    183     * cleared to be reused)
    184     */
    185    public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
    186    {
    187        this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
    188        return super.getCollisionBoundingBoxFromPool(par1World, par2, par3, par4);
    189    }
    190
    191    /**
    192     * Updates the blocks bounds based on its current state. Args: world, x, y, z
    193     */
    194    public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    195    {
    196        this.setDoorRotation(this.getFullMetadata(par1IBlockAccess, par2, par3, par4));
    197    }
    198
    199    /**
    200     * Returns 0, 1, 2 or 3 depending on where the hinge is.
    201     */
    202    public int getDoorOrientation(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    203    {
    204        return this.getFullMetadata(par1IBlockAccess, par2, par3, par4) & 3;
    205    }
    206
    207    public boolean isDoorOpen(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    208    {
    209        return (this.getFullMetadata(par1IBlockAccess, par2, par3, par4) & 4) != 0;
    210    }
    211
    212    private void setDoorRotation(int par1)
    213    {
    214        float f = 0.1875F;
    215        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 2.0F, 1.0F);
    216        int j = par1 & 3;
    217        boolean flag = (par1 & 4) != 0;
    218        boolean flag1 = (par1 & 16) != 0;
    219
    220        if (j == 0)
    221        {
    222            if (flag)
    223            {
    224                if (!flag1)
    225                {
    226                    this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
    227                }
    228                else
    229                {
    230                    this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
    231                }
    232            }
    233            else
    234            {
    235                this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
    236            }
    237        }
    238        else if (j == 1)
    239        {
    240            if (flag)
    241            {
    242                if (!flag1)
    243                {
    244                    this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    245                }
    246                else
    247                {
    248                    this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
    249                }
    250            }
    251            else
    252            {
    253                this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
    254            }
    255        }
    256        else if (j == 2)
    257        {
    258            if (flag)
    259            {
    260                if (!flag1)
    261                {
    262                    this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
    263                }
    264                else
    265                {
    266                    this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
    267                }
    268            }
    269            else
    270            {
    271                this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    272            }
    273        }
    274        else if (j == 3)
    275        {
    276            if (flag)
    277            {
    278                if (!flag1)
    279                {
    280                    this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
    281                }
    282                else
    283                {
    284                    this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    285                }
    286            }
    287            else
    288            {
    289                this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
    290            }
    291        }
    292    }
    293
    294    /**
    295     * Called when the block is clicked by a player. Args: x, y, z, entityPlayer
    296     */
    297    public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer) {}
    298
    299    /**
    300     * Called upon block activation (right click on the block.)
    301     */
    302    public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    303    {
    304        if (this.blockMaterial == Material.iron)
    305        {
    306            return false; //Allow items to interact with the door
    307        }
    308        else
    309        {
    310            int i1 = this.getFullMetadata(par1World, par2, par3, par4);
    311            int j1 = i1 & 7;
    312            j1 ^= 4;
    313
    314            if ((i1 & 8) == 0)
    315            {
    316                par1World.setBlockMetadataWithNotify(par2, par3, par4, j1, 2);
    317                par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4);
    318            }
    319            else
    320            {
    321                par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, j1, 2);
    322                par1World.markBlockRangeForRenderUpdate(par2, par3 - 1, par4, par2, par3, par4);
    323            }
    324
    325            par1World.playAuxSFXAtEntity(par5EntityPlayer, 1003, par2, par3, par4, 0);
    326            return true;
    327        }
    328    }
    329
    330    /**
    331     * A function to open a door.
    332     */
    333    public void onPoweredBlockChange(World par1World, int par2, int par3, int par4, boolean par5)
    334    {
    335        int l = this.getFullMetadata(par1World, par2, par3, par4);
    336        boolean flag1 = (l & 4) != 0;
    337
    338        if (flag1 != par5)
    339        {
    340            int i1 = l & 7;
    341            i1 ^= 4;
    342
    343            if ((l & 8) == 0)
    344            {
    345                par1World.setBlockMetadataWithNotify(par2, par3, par4, i1, 2);
    346                par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4);
    347            }
    348            else
    349            {
    350                par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, i1, 2);
    351                par1World.markBlockRangeForRenderUpdate(par2, par3 - 1, par4, par2, par3, par4);
    352            }
    353
    354            par1World.playAuxSFXAtEntity((EntityPlayer)null, 1003, par2, par3, par4, 0);
    355        }
    356    }
    357
    358    /**
    359     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
    360     * their own) Args: x, y, z, neighbor blockID
    361     */
    362    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
    363    {
    364        int i1 = par1World.getBlockMetadata(par2, par3, par4);
    365
    366        if ((i1 & 8) == 0)
    367        {
    368            boolean flag = false;
    369
    370            if (par1World.getBlockId(par2, par3 + 1, par4) != this.blockID)
    371            {
    372                par1World.setBlockToAir(par2, par3, par4);
    373                flag = true;
    374            }
    375
    376            if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4))
    377            {
    378                par1World.setBlockToAir(par2, par3, par4);
    379                flag = true;
    380
    381                if (par1World.getBlockId(par2, par3 + 1, par4) == this.blockID)
    382                {
    383                    par1World.setBlockToAir(par2, par3 + 1, par4);
    384                }
    385            }
    386
    387            if (flag)
    388            {
    389                if (!par1World.isRemote)
    390                {
    391                    this.dropBlockAsItem(par1World, par2, par3, par4, i1, 0);
    392                }
    393            }
    394            else
    395            {
    396                boolean flag1 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4);
    397
    398                if ((flag1 || par5 > 0 && Block.blocksList[par5].canProvidePower()) && par5 != this.blockID)
    399                {
    400                    this.onPoweredBlockChange(par1World, par2, par3, par4, flag1);
    401                }
    402            }
    403        }
    404        else
    405        {
    406            if (par1World.getBlockId(par2, par3 - 1, par4) != this.blockID)
    407            {
    408                par1World.setBlockToAir(par2, par3, par4);
    409            }
    410
    411            if (par5 > 0 && par5 != this.blockID)
    412            {
    413                this.onNeighborBlockChange(par1World, par2, par3 - 1, par4, par5);
    414            }
    415        }
    416    }
    417
    418    /**
    419     * Returns the ID of the items to drop on destruction.
    420     */
    421    public int idDropped(int par1, Random par2Random, int par3)
    422    {
    423        return (par1 & 8) != 0 ? 0 : (this.blockMaterial == Material.iron ? Item.doorIron.itemID : Item.doorWood.itemID);
    424    }
    425
    426    /**
    427     * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world,
    428     * x, y, z, startVec, endVec
    429     */
    430    public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3)
    431    {
    432        this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
    433        return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3);
    434    }
    435
    436    /**
    437     * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
    438     */
    439    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
    440    {
    441        return par3 >= 255 ? false : par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && super.canPlaceBlockAt(par1World, par2, par3, par4) && super.canPlaceBlockAt(par1World, par2, par3 + 1, par4);
    442    }
    443
    444    /**
    445     * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
    446     * and stop pistons
    447     */
    448    public int getMobilityFlag()
    449    {
    450        return 1;
    451    }
    452
    453    /**
    454     * Returns the full metadata value created by combining the metadata of both blocks the door takes up.
    455     */
    456    public int getFullMetadata(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    457    {
    458        int l = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
    459        boolean flag = (l & 8) != 0;
    460        int i1;
    461        int j1;
    462
    463        if (flag)
    464        {
    465            i1 = par1IBlockAccess.getBlockMetadata(par2, par3 - 1, par4);
    466            j1 = l;
    467        }
    468        else
    469        {
    470            i1 = l;
    471            j1 = par1IBlockAccess.getBlockMetadata(par2, par3 + 1, par4);
    472        }
    473
    474        boolean flag1 = (j1 & 1) != 0;
    475        return i1 & 7 | (flag ? 8 : 0) | (flag1 ? 16 : 0);
    476    }
    477
    478    @SideOnly(Side.CLIENT)
    479
    480    /**
    481     * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
    482     */
    483    public int idPicked(World par1World, int par2, int par3, int par4)
    484    {
    485        return this.blockMaterial == Material.iron ? Item.doorIron.itemID : Item.doorWood.itemID;
    486    }
    487
    488    /**
    489     * Called when the block is attempted to be harvested
    490     */
    491    public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
    492    {
    493        if (par6EntityPlayer.capabilities.isCreativeMode && (par5 & 8) != 0 && par1World.getBlockId(par2, par3 - 1, par4) == this.blockID)
    494        {
    495            par1World.setBlockToAir(par2, par3 - 1, par4);
    496        }
    497    }
    498}