    001package net.minecraft.block;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.Iterator;
    006import java.util.Random;
    007import net.minecraft.block.material.Material;
    008import net.minecraft.client.renderer.texture.IconRegister;
    009import net.minecraft.creativetab.CreativeTabs;
    010import net.minecraft.entity.EntityLiving;
    011import net.minecraft.entity.item.EntityItem;
    012import net.minecraft.entity.passive.EntityOcelot;
    013import net.minecraft.entity.player.EntityPlayer;
    014import net.minecraft.inventory.Container;
    015import net.minecraft.inventory.IInventory;
    016import net.minecraft.inventory.InventoryLargeChest;
    017import net.minecraft.item.ItemStack;
    018import net.minecraft.nbt.NBTTagCompound;
    019import net.minecraft.tileentity.TileEntity;
    020import net.minecraft.tileentity.TileEntityChest;
    021import net.minecraft.util.AxisAlignedBB;
    022import net.minecraft.util.MathHelper;
    023import net.minecraft.world.IBlockAccess;
    024import net.minecraft.world.World;
    025
    026import static net.minecraftforge.common.ForgeDirection.*;
    027
    028public class BlockChest extends BlockContainer
    029{
    030    private final Random random = new Random();
    031    public final int field_94443_a;
    032
    033    protected BlockChest(int par1, int par2)
    034    {
    035        super(par1, Material.wood);
    036        this.field_94443_a = par2;
    037        this.setCreativeTab(CreativeTabs.tabDecorations);
    038        this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 0.9375F, 0.875F, 0.9375F);
    039    }
    040
    041    /**
    042     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    043     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    044     */
    045    public boolean isOpaqueCube()
    046    {
    047        return false;
    048    }
    049
    050    /**
    051     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
    052     */
    053    public boolean renderAsNormalBlock()
    054    {
    055        return false;
    056    }
    057
    058    /**
    059     * The type of render function that is called for this block
    060     */
    061    public int getRenderType()
    062    {
    063        return 22;
    064    }
    065
    066    /**
    067     * Updates the blocks bounds based on its current state. Args: world, x, y, z
    068     */
    069    public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    070    {
    071        if (par1IBlockAccess.getBlockId(par2, par3, par4 - 1) == this.blockID)
    072        {
    073            this.setBlockBounds(0.0625F, 0.0F, 0.0F, 0.9375F, 0.875F, 0.9375F);
    074        }
    075        else if (par1IBlockAccess.getBlockId(par2, par3, par4 + 1) == this.blockID)
    076        {
    077            this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 0.9375F, 0.875F, 1.0F);
    078        }
    079        else if (par1IBlockAccess.getBlockId(par2 - 1, par3, par4) == this.blockID)
    080        {
    081            this.setBlockBounds(0.0F, 0.0F, 0.0625F, 0.9375F, 0.875F, 0.9375F);
    082        }
    083        else if (par1IBlockAccess.getBlockId(par2 + 1, par3, par4) == this.blockID)
    084        {
    085            this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 1.0F, 0.875F, 0.9375F);
    086        }
    087        else
    088        {
    089            this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 0.9375F, 0.875F, 0.9375F);
    090        }
    091    }
    092
    093    /**
    094     * Called whenever the block is added into the world. Args: world, x, y, z
    095     */
    096    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    097    {
    098        super.onBlockAdded(par1World, par2, par3, par4);
    099        this.unifyAdjacentChests(par1World, par2, par3, par4);
    100        int l = par1World.getBlockId(par2, par3, par4 - 1);
    101        int i1 = par1World.getBlockId(par2, par3, par4 + 1);
    102        int j1 = par1World.getBlockId(par2 - 1, par3, par4);
    103        int k1 = par1World.getBlockId(par2 + 1, par3, par4);
    104
    105        if (l == this.blockID)
    106        {
    107            this.unifyAdjacentChests(par1World, par2, par3, par4 - 1);
    108        }
    109
    110        if (i1 == this.blockID)
    111        {
    112            this.unifyAdjacentChests(par1World, par2, par3, par4 + 1);
    113        }
    114
    115        if (j1 == this.blockID)
    116        {
    117            this.unifyAdjacentChests(par1World, par2 - 1, par3, par4);
    118        }
    119
    120        if (k1 == this.blockID)
    121        {
    122            this.unifyAdjacentChests(par1World, par2 + 1, par3, par4);
    123        }
    124    }
    125
    126    /**
    127     * Called when the block is placed in the world.
    128     */
    129    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack)
    130    {
    131        int l = par1World.getBlockId(par2, par3, par4 - 1);
    132        int i1 = par1World.getBlockId(par2, par3, par4 + 1);
    133        int j1 = par1World.getBlockId(par2 - 1, par3, par4);
    134        int k1 = par1World.getBlockId(par2 + 1, par3, par4);
    135        byte b0 = 0;
    136        int l1 = MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
    137
    138        if (l1 == 0)
    139        {
    140            b0 = 2;
    141        }
    142
    143        if (l1 == 1)
    144        {
    145            b0 = 5;
    146        }
    147
    148        if (l1 == 2)
    149        {
    150            b0 = 3;
    151        }
    152
    153        if (l1 == 3)
    154        {
    155            b0 = 4;
    156        }
    157
    158        if (l != this.blockID && i1 != this.blockID && j1 != this.blockID && k1 != this.blockID)
    159        {
    160            par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 3);
    161        }
    162        else
    163        {
    164            if ((l == this.blockID || i1 == this.blockID) && (b0 == 4 || b0 == 5))
    165            {
    166                if (l == this.blockID)
    167                {
    168                    par1World.setBlockMetadataWithNotify(par2, par3, par4 - 1, b0, 3);
    169                }
    170                else
    171                {
    172                    par1World.setBlockMetadataWithNotify(par2, par3, par4 + 1, b0, 3);
    173                }
    174
    175                par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 3);
    176            }
    177
    178            if ((j1 == this.blockID || k1 == this.blockID) && (b0 == 2 || b0 == 3))
    179            {
    180                if (j1 == this.blockID)
    181                {
    182                    par1World.setBlockMetadataWithNotify(par2 - 1, par3, par4, b0, 3);
    183                }
    184                else
    185                {
    186                    par1World.setBlockMetadataWithNotify(par2 + 1, par3, par4, b0, 3);
    187                }
    188
    189                par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 3);
    190            }
    191        }
    192
    193        if (par6ItemStack.hasDisplayName())
    194        {
    195            ((TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4)).func_94043_a(par6ItemStack.getDisplayName());
    196        }
    197    }
    198
    199    /**
    200     * Turns the adjacent chests to a double chest.
    201     */
    202    public void unifyAdjacentChests(World par1World, int par2, int par3, int par4)
    203    {
    204        if (!par1World.isRemote)
    205        {
    206            int l = par1World.getBlockId(par2, par3, par4 - 1);
    207            int i1 = par1World.getBlockId(par2, par3, par4 + 1);
    208            int j1 = par1World.getBlockId(par2 - 1, par3, par4);
    209            int k1 = par1World.getBlockId(par2 + 1, par3, par4);
    210            boolean flag = true;
    211            int l1;
    212            int i2;
    213            boolean flag1;
    214            byte b0;
    215            int j2;
    216
    217            if (l != this.blockID && i1 != this.blockID)
    218            {
    219                if (j1 != this.blockID && k1 != this.blockID)
    220                {
    221                    b0 = 3;
    222
    223                    if (Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[i1])
    224                    {
    225                        b0 = 3;
    226                    }
    227
    228                    if (Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[l])
    229                    {
    230                        b0 = 2;
    231                    }
    232
    233                    if (Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[k1])
    234                    {
    235                        b0 = 5;
    236                    }
    237
    238                    if (Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[j1])
    239                    {
    240                        b0 = 4;
    241                    }
    242                }
    243                else
    244                {
    245                    l1 = par1World.getBlockId(j1 == this.blockID ? par2 - 1 : par2 + 1, par3, par4 - 1);
    246                    i2 = par1World.getBlockId(j1 == this.blockID ? par2 - 1 : par2 + 1, par3, par4 + 1);
    247                    b0 = 3;
    248                    flag1 = true;
    249
    250                    if (j1 == this.blockID)
    251                    {
    252                        j2 = par1World.getBlockMetadata(par2 - 1, par3, par4);
    253                    }
    254                    else
    255                    {
    256                        j2 = par1World.getBlockMetadata(par2 + 1, par3, par4);
    257                    }
    258
    259                    if (j2 == 2)
    260                    {
    261                        b0 = 2;
    262                    }
    263
    264                    if ((Block.opaqueCubeLookup[l] || Block.opaqueCubeLookup[l1]) && !Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[i2])
    265                    {
    266                        b0 = 3;
    267                    }
    268
    269                    if ((Block.opaqueCubeLookup[i1] || Block.opaqueCubeLookup[i2]) && !Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[l1])
    270                    {
    271                        b0 = 2;
    272                    }
    273                }
    274            }
    275            else
    276            {
    277                l1 = par1World.getBlockId(par2 - 1, par3, l == this.blockID ? par4 - 1 : par4 + 1);
    278                i2 = par1World.getBlockId(par2 + 1, par3, l == this.blockID ? par4 - 1 : par4 + 1);
    279                b0 = 5;
    280                flag1 = true;
    281
    282                if (l == this.blockID)
    283                {
    284                    j2 = par1World.getBlockMetadata(par2, par3, par4 - 1);
    285                }
    286                else
    287                {
    288                    j2 = par1World.getBlockMetadata(par2, par3, par4 + 1);
    289                }
    290
    291                if (j2 == 4)
    292                {
    293                    b0 = 4;
    294                }
    295
    296                if ((Block.opaqueCubeLookup[j1] || Block.opaqueCubeLookup[l1]) && !Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[i2])
    297                {
    298                    b0 = 5;
    299                }
    300
    301                if ((Block.opaqueCubeLookup[k1] || Block.opaqueCubeLookup[i2]) && !Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[l1])
    302                {
    303                    b0 = 4;
    304                }
    305            }
    306
    307            par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 3);
    308        }
    309    }
    310
    311    /**
    312     * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
    313     */
    314    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
    315    {
    316        int l = 0;
    317
    318        if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID)
    319        {
    320            ++l;
    321        }
    322
    323        if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID)
    324        {
    325            ++l;
    326        }
    327
    328        if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID)
    329        {
    330            ++l;
    331        }
    332
    333        if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)
    334        {
    335            ++l;
    336        }
    337
    338        return l > 1 ? false : (this.isThereANeighborChest(par1World, par2 - 1, par3, par4) ? false : (this.isThereANeighborChest(par1World, par2 + 1, par3, par4) ? false : (this.isThereANeighborChest(par1World, par2, par3, par4 - 1) ? false : !this.isThereANeighborChest(par1World, par2, par3, par4 + 1))));
    339    }
    340
    341    /**
    342     * Checks the neighbor blocks to see if there is a chest there. Args: world, x, y, z
    343     */
    344    private boolean isThereANeighborChest(World par1World, int par2, int par3, int par4)
    345    {
    346        return par1World.getBlockId(par2, par3, par4) != this.blockID ? false : (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID ? true : (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID ? true : (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID ? true : par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)));
    347    }
    348
    349    /**
    350     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
    351     * their own) Args: x, y, z, neighbor blockID
    352     */
    353    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
    354    {
    355        super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
    356        TileEntityChest tileentitychest = (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4);
    357
    358        if (tileentitychest != null)
    359        {
    360            tileentitychest.updateContainingBlockInfo();
    361        }
    362    }
    363
    364    /**
    365     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
    366     */
    367    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
    368    {
    369        TileEntityChest tileentitychest = (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4);
    370
    371        if (tileentitychest != null)
    372        {
    373            for (int j1 = 0; j1 < tileentitychest.getSizeInventory(); ++j1)
    374            {
    375                ItemStack itemstack = tileentitychest.getStackInSlot(j1);
    376
    377                if (itemstack != null)
    378                {
    379                    float f = this.random.nextFloat() * 0.8F + 0.1F;
    380                    float f1 = this.random.nextFloat() * 0.8F + 0.1F;
    381                    EntityItem entityitem;
    382
    383                    for (float f2 = this.random.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; par1World.spawnEntityInWorld(entityitem))
    384                    {
    385                        int k1 = this.random.nextInt(21) + 10;
    386
    387                        if (k1 > itemstack.stackSize)
    388                        {
    389                            k1 = itemstack.stackSize;
    390                        }
    391
    392                        itemstack.stackSize -= k1;
    393                        entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage()));
    394                        float f3 = 0.05F;
    395                        entityitem.motionX = (double)((float)this.random.nextGaussian() * f3);
    396                        entityitem.motionY = (double)((float)this.random.nextGaussian() * f3 + 0.2F);
    397                        entityitem.motionZ = (double)((float)this.random.nextGaussian() * f3);
    398
    399                        if (itemstack.hasTagCompound())
    400                        {
    401                            entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
    402                        }
    403                    }
    404                }
    405            }
    406        }
    407
    408        super.breakBlock(par1World, par2, par3, par4, par5, par6);
    409    }
    410
    411    /**
    412     * Called upon block activation (right click on the block.)
    413     */
    414    public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    415    {
    416        if (par1World.isRemote)
    417        {
    418            return true;
    419        }
    420        else
    421        {
    422            IInventory iinventory = this.func_94442_h_(par1World, par2, par3, par4);
    423
    424            if (iinventory != null)
    425            {
    426                par5EntityPlayer.displayGUIChest(iinventory);
    427            }
    428
    429            return true;
    430        }
    431    }
    432
    433    public IInventory func_94442_h_(World par1World, int par2, int par3, int par4)
    434    {
    435        Object object = (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4);
    436
    437        if (object == null)
    438        {
    439            return null;
    440        }
    441        else if (par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN))
    442        {
    443            return null;
    444        }
    445        else if (isOcelotBlockingChest(par1World, par2, par3, par4))
    446        {
    447            return null;
    448        }
    449        else if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 - 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 - 1, par3, par4)))
    450        {
    451            return null;
    452        }
    453        else if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 + 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 + 1, par3, par4)))
    454        {
    455            return null;
    456        }
    457        else if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 - 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 - 1)))
    458        {
    459            return null;
    460        }
    461        else if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 + 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 + 1)))
    462        {
    463            return null;
    464        }
    465        else
    466        {
    467            if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID)
    468            {
    469                object = new InventoryLargeChest("container.chestDouble", (TileEntityChest)par1World.getBlockTileEntity(par2 - 1, par3, par4), (IInventory)object);
    470            }
    471
    472            if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID)
    473            {
    474                object = new InventoryLargeChest("container.chestDouble", (IInventory)object, (TileEntityChest)par1World.getBlockTileEntity(par2 + 1, par3, par4));
    475            }
    476
    477            if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID)
    478            {
    479                object = new InventoryLargeChest("container.chestDouble", (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4 - 1), (IInventory)object);
    480            }
    481
    482            if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)
    483            {
    484                object = new InventoryLargeChest("container.chestDouble", (IInventory)object, (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4 + 1));
    485            }
    486
    487            return (IInventory)object;
    488        }
    489    }
    490
    491    /**
    492     * Returns a new instance of a block's tile entity class. Called on placing the block.
    493     */
    494    public TileEntity createNewTileEntity(World par1World)
    495    {
    496        TileEntityChest tileentitychest = new TileEntityChest();
    497        return tileentitychest;
    498    }
    499
    500    /**
    501     * Can this block provide power. Only wire currently seems to have this change based on its state.
    502     */
    503    public boolean canProvidePower()
    504    {
    505        return this.field_94443_a == 1;
    506    }
    507
    508    /**
    509     * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube
    510     * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X,
    511     * Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
    512     */
    513    public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    514    {
    515        if (!this.canProvidePower())
    516        {
    517            return 0;
    518        }
    519        else
    520        {
    521            int i1 = ((TileEntityChest)par1IBlockAccess.getBlockTileEntity(par2, par3, par4)).numUsingPlayers;
    522            return MathHelper.clamp_int(i1, 0, 15);
    523        }
    524    }
    525
    526    /**
    527     * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z,
    528     * side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
    529     */
    530    public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    531    {
    532        return par5 == 1 ? this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5) : 0;
    533    }
    534
    535    /**
    536     * Looks for a sitting ocelot within certain bounds. Such an ocelot is considered to be blocking access to the
    537     * chest.
    538     */
    539    public static boolean isOcelotBlockingChest(World par0World, int par1, int par2, int par3)
    540    {
    541        Iterator iterator = par0World.getEntitiesWithinAABB(EntityOcelot.class, AxisAlignedBB.getAABBPool().getAABB((double)par1, (double)(par2 + 1), (double)par3, (double)(par1 + 1), (double)(par2 + 2), (double)(par3 + 1))).iterator();
    542        EntityOcelot entityocelot;
    543
    544        do
    545        {
    546            if (!iterator.hasNext())
    547            {
    548                return false;
    549            }
    550
    551            EntityOcelot entityocelot1 = (EntityOcelot)iterator.next();
    552            entityocelot = (EntityOcelot)entityocelot1;
    553        }
    554        while (!entityocelot.isSitting());
    555
    556        return true;
    557    }
    558
    559    public boolean func_96468_q_()
    560    {
    561        return true;
    562    }
    563
    564    public int func_94328_b_(World par1World, int par2, int par3, int par4, int par5)
    565    {
    566        return Container.func_94526_b(this.func_94442_h_(par1World, par2, par3, par4));
    567    }
    568
    569    @SideOnly(Side.CLIENT)
    570    public void func_94332_a(IconRegister par1IconRegister)
    571    {
    572        this.field_94336_cN = par1IconRegister.func_94245_a("wood");
    573    }
    574}