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.texture.IconRegister;
008import net.minecraft.creativetab.CreativeTabs;
009import net.minecraft.dispenser.BehaviorDefaultDispenseItem;
010import net.minecraft.dispenser.IBehaviorDispenseItem;
011import net.minecraft.dispenser.IBlockSource;
012import net.minecraft.dispenser.IPosition;
013import net.minecraft.dispenser.IRegistry;
014import net.minecraft.dispenser.PositionImpl;
015import net.minecraft.dispenser.RegistryDefaulted;
016import net.minecraft.entity.EntityLiving;
017import net.minecraft.entity.item.EntityItem;
018import net.minecraft.entity.player.EntityPlayer;
019import net.minecraft.inventory.Container;
020import net.minecraft.inventory.IInventory;
021import net.minecraft.item.ItemStack;
022import net.minecraft.nbt.NBTTagCompound;
023import net.minecraft.tileentity.TileEntity;
024import net.minecraft.tileentity.TileEntityDispenser;
025import net.minecraft.util.EnumFacing;
026import net.minecraft.util.Icon;
027import net.minecraft.world.World;
028
029public class BlockDispenser extends BlockContainer
030{
031    /** Registry for all dispense behaviors. */
032    public static final IRegistry dispenseBehaviorRegistry = new RegistryDefaulted(new BehaviorDefaultDispenseItem());
033    protected Random random = new Random();
034    @SideOnly(Side.CLIENT)
035    protected Icon field_94463_c;
036    @SideOnly(Side.CLIENT)
037    protected Icon field_94462_cO;
038    @SideOnly(Side.CLIENT)
039    protected Icon field_96473_e;
040
041    protected BlockDispenser(int par1)
042    {
043        super(par1, Material.rock);
044        this.setCreativeTab(CreativeTabs.tabRedstone);
045    }
046
047    /**
048     * How many world ticks before ticking
049     */
050    public int tickRate(World par1World)
051    {
052        return 4;
053    }
054
055    /**
056     * Called whenever the block is added into the world. Args: world, x, y, z
057     */
058    public void onBlockAdded(World par1World, int par2, int par3, int par4)
059    {
060        super.onBlockAdded(par1World, par2, par3, par4);
061        this.setDispenserDefaultDirection(par1World, par2, par3, par4);
062    }
063
064    /**
065     * sets Dispenser block direction so that the front faces an non-opaque block; chooses west to be direction if all
066     * surrounding blocks are opaque.
067     */
068    private void setDispenserDefaultDirection(World par1World, int par2, int par3, int par4)
069    {
070        if (!par1World.isRemote)
071        {
072            int l = par1World.getBlockId(par2, par3, par4 - 1);
073            int i1 = par1World.getBlockId(par2, par3, par4 + 1);
074            int j1 = par1World.getBlockId(par2 - 1, par3, par4);
075            int k1 = par1World.getBlockId(par2 + 1, par3, par4);
076            byte b0 = 3;
077
078            if (Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[i1])
079            {
080                b0 = 3;
081            }
082
083            if (Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[l])
084            {
085                b0 = 2;
086            }
087
088            if (Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[k1])
089            {
090                b0 = 5;
091            }
092
093            if (Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[j1])
094            {
095                b0 = 4;
096            }
097
098            par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 2);
099        }
100    }
101
102    @SideOnly(Side.CLIENT)
103
104    /**
105     * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
106     */
107    public Icon getBlockTextureFromSideAndMetadata(int par1, int par2)
108    {
109        int k = par2 & 7;
110        return par1 == k ? (k != 1 && k != 0 ? this.field_94462_cO : this.field_96473_e) : (k != 1 && k != 0 ? (par1 != 1 && par1 != 0 ? this.field_94336_cN : this.field_94463_c) : this.field_94463_c);
111    }
112
113    @SideOnly(Side.CLIENT)
114    public void func_94332_a(IconRegister par1IconRegister)
115    {
116        this.field_94336_cN = par1IconRegister.func_94245_a("furnace_side");
117        this.field_94463_c = par1IconRegister.func_94245_a("furnace_top");
118        this.field_94462_cO = par1IconRegister.func_94245_a("dispenser_front");
119        this.field_96473_e = par1IconRegister.func_94245_a("dispenser_front_vertical");
120    }
121
122    /**
123     * Called upon block activation (right click on the block.)
124     */
125    public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
126    {
127        if (par1World.isRemote)
128        {
129            return true;
130        }
131        else
132        {
133            TileEntityDispenser tileentitydispenser = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4);
134
135            if (tileentitydispenser != null)
136            {
137                par5EntityPlayer.displayGUIDispenser(tileentitydispenser);
138            }
139
140            return true;
141        }
142    }
143
144    protected void dispense(World par1World, int par2, int par3, int par4)
145    {
146        BlockSourceImpl blocksourceimpl = new BlockSourceImpl(par1World, par2, par3, par4);
147        TileEntityDispenser tileentitydispenser = (TileEntityDispenser)blocksourceimpl.func_82619_j();
148
149        if (tileentitydispenser != null)
150        {
151            int l = tileentitydispenser.getRandomStackFromInventory();
152
153            if (l < 0)
154            {
155                par1World.playAuxSFX(1001, par2, par3, par4, 0);
156            }
157            else
158            {
159                ItemStack itemstack = tileentitydispenser.getStackInSlot(l);
160                IBehaviorDispenseItem ibehaviordispenseitem = this.func_96472_a(itemstack);
161
162                if (ibehaviordispenseitem != IBehaviorDispenseItem.itemDispenseBehaviorProvider)
163                {
164                    ItemStack itemstack1 = ibehaviordispenseitem.dispense(blocksourceimpl, itemstack);
165                    tileentitydispenser.setInventorySlotContents(l, itemstack1.stackSize == 0 ? null : itemstack1);
166                }
167            }
168        }
169    }
170
171    protected IBehaviorDispenseItem func_96472_a(ItemStack par1ItemStack)
172    {
173        return (IBehaviorDispenseItem)dispenseBehaviorRegistry.func_82594_a(par1ItemStack.getItem());
174    }
175
176    /**
177     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
178     * their own) Args: x, y, z, neighbor blockID
179     */
180    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
181    {
182        boolean flag = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4);
183        int i1 = par1World.getBlockMetadata(par2, par3, par4);
184        boolean flag1 = (i1 & 8) != 0;
185
186        if (flag && !flag1)
187        {
188            par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate(par1World));
189            par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 | 8, 4);
190        }
191        else if (!flag && flag1)
192        {
193            par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 & -9, 4);
194        }
195    }
196
197    /**
198     * Ticks the block if it's been scheduled
199     */
200    public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
201    {
202        if (!par1World.isRemote)
203        {
204            this.dispense(par1World, par2, par3, par4);
205        }
206    }
207
208    /**
209     * Returns a new instance of a block's tile entity class. Called on placing the block.
210     */
211    public TileEntity createNewTileEntity(World par1World)
212    {
213        return new TileEntityDispenser();
214    }
215
216    /**
217     * Called when the block is placed in the world.
218     */
219    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack)
220    {
221        int l = BlockPistonBase.determineOrientation(par1World, par2, par3, par4, par5EntityLiving);
222        par1World.setBlockMetadataWithNotify(par2, par3, par4, l, 2);
223
224        if (par6ItemStack.hasDisplayName())
225        {
226            ((TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4)).func_94049_a(par6ItemStack.getDisplayName());
227        }
228    }
229
230    /**
231     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
232     */
233    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
234    {
235        TileEntityDispenser tileentitydispenser = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4);
236
237        if (tileentitydispenser != null)
238        {
239            for (int j1 = 0; j1 < tileentitydispenser.getSizeInventory(); ++j1)
240            {
241                ItemStack itemstack = tileentitydispenser.getStackInSlot(j1);
242
243                if (itemstack != null)
244                {
245                    float f = this.random.nextFloat() * 0.8F + 0.1F;
246                    float f1 = this.random.nextFloat() * 0.8F + 0.1F;
247                    float f2 = this.random.nextFloat() * 0.8F + 0.1F;
248
249                    while (itemstack.stackSize > 0)
250                    {
251                        int k1 = this.random.nextInt(21) + 10;
252
253                        if (k1 > itemstack.stackSize)
254                        {
255                            k1 = itemstack.stackSize;
256                        }
257
258                        itemstack.stackSize -= k1;
259                        EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage()));
260
261                        if (itemstack.hasTagCompound())
262                        {
263                            entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
264                        }
265
266                        float f3 = 0.05F;
267                        entityitem.motionX = (double)((float)this.random.nextGaussian() * f3);
268                        entityitem.motionY = (double)((float)this.random.nextGaussian() * f3 + 0.2F);
269                        entityitem.motionZ = (double)((float)this.random.nextGaussian() * f3);
270                        par1World.spawnEntityInWorld(entityitem);
271                    }
272                }
273            }
274        }
275
276        super.breakBlock(par1World, par2, par3, par4, par5, par6);
277    }
278
279    public static IPosition getIPositionFromBlockSource(IBlockSource par0IBlockSource)
280    {
281        EnumFacing enumfacing = func_100009_j_(par0IBlockSource.func_82620_h());
282        double d0 = par0IBlockSource.getX() + 0.7D * (double)enumfacing.getFrontOffsetX();
283        double d1 = par0IBlockSource.getY() + 0.7D * (double)enumfacing.func_96559_d();
284        double d2 = par0IBlockSource.getZ() + 0.7D * (double)enumfacing.getFrontOffsetZ();
285        return new PositionImpl(d0, d1, d2);
286    }
287
288    public static EnumFacing func_100009_j_(int par0)
289    {
290        return EnumFacing.getFront(par0 & 7);
291    }
292
293    public boolean func_96468_q_()
294    {
295        return true;
296    }
297
298    public int func_94328_b_(World par1World, int par2, int par3, int par4, int par5)
299    {
300        return Container.func_94526_b((IInventory)par1World.getBlockTileEntity(par2, par3, par4));
301    }
302}