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