    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            par1World.func_96440_m(par2, par3, par4, par5);
    408        }
    409
    410        super.breakBlock(par1World, par2, par3, par4, par5, par6);
    411    }
    412
    413    /**
    414     * Called upon block activation (right click on the block.)
    415     */
    416    public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    417    {
    418        if (par1World.isRemote)
    419        {
    420            return true;
    421        }
    422        else
    423        {
    424            IInventory iinventory = this.getInventory(par1World, par2, par3, par4);
    425
    426            if (iinventory != null)
    427            {
    428                par5EntityPlayer.displayGUIChest(iinventory);
    429            }
    430
    431            return true;
    432        }
    433    }
    434
    435    /**
    436     * Gets the inventory of the chest at the specified coords, accounting for blocks or ocelots on top of the chest,
    437     * and double chests.
    438     */
    439    public IInventory getInventory(World par1World, int par2, int par3, int par4)
    440    {
    441        Object object = (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4);
    442
    443        if (object == null)
    444        {
    445            return null;
    446        }
    447        else if (par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN))
    448        {
    449            return null;
    450        }
    451        else if (isOcelotBlockingChest(par1World, par2, par3, par4))
    452        {
    453            return null;
    454        }
    455        else if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 - 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 - 1, par3, par4)))
    456        {
    457            return null;
    458        }
    459        else if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 + 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 + 1, par3, par4)))
    460        {
    461            return null;
    462        }
    463        else if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 - 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 - 1)))
    464        {
    465            return null;
    466        }
    467        else if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 + 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 + 1)))
    468        {
    469            return null;
    470        }
    471        else
    472        {
    473            if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID)
    474            {
    475                object = new InventoryLargeChest("container.chestDouble", (TileEntityChest)par1World.getBlockTileEntity(par2 - 1, par3, par4), (IInventory)object);
    476            }
    477
    478            if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID)
    479            {
    480                object = new InventoryLargeChest("container.chestDouble", (IInventory)object, (TileEntityChest)par1World.getBlockTileEntity(par2 + 1, par3, par4));
    481            }
    482
    483            if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID)
    484            {
    485                object = new InventoryLargeChest("container.chestDouble", (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4 - 1), (IInventory)object);
    486            }
    487
    488            if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)
    489            {
    490                object = new InventoryLargeChest("container.chestDouble", (IInventory)object, (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4 + 1));
    491            }
    492
    493            return (IInventory)object;
    494        }
    495    }
    496
    497    /**
    498     * Returns a new instance of a block's tile entity class. Called on placing the block.
    499     */
    500    public TileEntity createNewTileEntity(World par1World)
    501    {
    502        TileEntityChest tileentitychest = new TileEntityChest();
    503        return tileentitychest;
    504    }
    505
    506    /**
    507     * Can this block provide power. Only wire currently seems to have this change based on its state.
    508     */
    509    public boolean canProvidePower()
    510    {
    511        return this.field_94443_a == 1;
    512    }
    513
    514    /**
    515     * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube
    516     * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X,
    517     * Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
    518     */
    519    public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    520    {
    521        if (!this.canProvidePower())
    522        {
    523            return 0;
    524        }
    525        else
    526        {
    527            int i1 = ((TileEntityChest)par1IBlockAccess.getBlockTileEntity(par2, par3, par4)).numUsingPlayers;
    528            return MathHelper.clamp_int(i1, 0, 15);
    529        }
    530    }
    531
    532    /**
    533     * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z,
    534     * side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
    535     */
    536    public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    537    {
    538        return par5 == 1 ? this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5) : 0;
    539    }
    540
    541    /**
    542     * Looks for a sitting ocelot within certain bounds. Such an ocelot is considered to be blocking access to the
    543     * chest.
    544     */
    545    public static boolean isOcelotBlockingChest(World par0World, int par1, int par2, int par3)
    546    {
    547        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();
    548        EntityOcelot entityocelot;
    549
    550        do
    551        {
    552            if (!iterator.hasNext())
    553            {
    554                return false;
    555            }
    556
    557            EntityOcelot entityocelot1 = (EntityOcelot)iterator.next();
    558            entityocelot = (EntityOcelot)entityocelot1;
    559        }
    560        while (!entityocelot.isSitting());
    561
    562        return true;
    563    }
    564
    565    /**
    566     * If this returns true, then comparators facing away from this block will use the value from
    567     * getComparatorInputOverride instead of the actual redstone signal strength.
    568     */
    569    public boolean hasComparatorInputOverride()
    570    {
    571        return true;
    572    }
    573
    574    /**
    575     * If hasComparatorInputOverride returns true, the return value from this is used instead of the redstone signal
    576     * strength when this block inputs to a comparator.
    577     */
    578    public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5)
    579    {
    580        return Container.func_94526_b(this.getInventory(par1World, par2, par3, par4));
    581    }
    582
    583    @SideOnly(Side.CLIENT)
    584
    585    /**
    586     * When this method is called, your block should register all the icons it needs with the given IconRegister. This
    587     * is the only chance you get to register icons.
    588     */
    589    public void registerIcons(IconRegister par1IconRegister)
    590    {
    591        this.blockIcon = par1IconRegister.registerIcon("wood");
    592    }
    593}