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.blockIcon : this.field_94463_c) : this.field_94463_c);
111    }
112
113    @SideOnly(Side.CLIENT)
114
115    /**
116     * When this method is called, your block should register all the icons it needs with the given IconRegister. This
117     * is the only chance you get to register icons.
118     */
119    public void registerIcons(IconRegister par1IconRegister)
120    {
121        this.blockIcon = par1IconRegister.registerIcon("furnace_side");
122        this.field_94463_c = par1IconRegister.registerIcon("furnace_top");
123        this.field_94462_cO = par1IconRegister.registerIcon("dispenser_front");
124        this.field_96473_e = par1IconRegister.registerIcon("dispenser_front_vertical");
125    }
126
127    /**
128     * Called upon block activation (right click on the block.)
129     */
130    public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
131    {
132        if (par1World.isRemote)
133        {
134            return true;
135        }
136        else
137        {
138            TileEntityDispenser tileentitydispenser = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4);
139
140            if (tileentitydispenser != null)
141            {
142                par5EntityPlayer.displayGUIDispenser(tileentitydispenser);
143            }
144
145            return true;
146        }
147    }
148
149    protected void dispense(World par1World, int par2, int par3, int par4)
150    {
151        BlockSourceImpl blocksourceimpl = new BlockSourceImpl(par1World, par2, par3, par4);
152        TileEntityDispenser tileentitydispenser = (TileEntityDispenser)blocksourceimpl.getBlockTileEntity();
153
154        if (tileentitydispenser != null)
155        {
156            int l = tileentitydispenser.getRandomStackFromInventory();
157
158            if (l < 0)
159            {
160                par1World.playAuxSFX(1001, par2, par3, par4, 0);
161            }
162            else
163            {
164                ItemStack itemstack = tileentitydispenser.getStackInSlot(l);
165                IBehaviorDispenseItem ibehaviordispenseitem = this.func_96472_a(itemstack);
166
167                if (ibehaviordispenseitem != IBehaviorDispenseItem.itemDispenseBehaviorProvider)
168                {
169                    ItemStack itemstack1 = ibehaviordispenseitem.dispense(blocksourceimpl, itemstack);
170                    tileentitydispenser.setInventorySlotContents(l, itemstack1.stackSize == 0 ? null : itemstack1);
171                }
172            }
173        }
174    }
175
176    protected IBehaviorDispenseItem func_96472_a(ItemStack par1ItemStack)
177    {
178        return (IBehaviorDispenseItem)dispenseBehaviorRegistry.func_82594_a(par1ItemStack.getItem());
179    }
180
181    /**
182     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
183     * their own) Args: x, y, z, neighbor blockID
184     */
185    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
186    {
187        boolean flag = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4);
188        int i1 = par1World.getBlockMetadata(par2, par3, par4);
189        boolean flag1 = (i1 & 8) != 0;
190
191        if (flag && !flag1)
192        {
193            par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate(par1World));
194            par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 | 8, 4);
195        }
196        else if (!flag && flag1)
197        {
198            par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 & -9, 4);
199        }
200    }
201
202    /**
203     * Ticks the block if it's been scheduled
204     */
205    public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
206    {
207        if (!par1World.isRemote)
208        {
209            this.dispense(par1World, par2, par3, par4);
210        }
211    }
212
213    /**
214     * Returns a new instance of a block's tile entity class. Called on placing the block.
215     */
216    public TileEntity createNewTileEntity(World par1World)
217    {
218        return new TileEntityDispenser();
219    }
220
221    /**
222     * Called when the block is placed in the world.
223     */
224    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack)
225    {
226        int l = BlockPistonBase.determineOrientation(par1World, par2, par3, par4, par5EntityLiving);
227        par1World.setBlockMetadataWithNotify(par2, par3, par4, l, 2);
228
229        if (par6ItemStack.hasDisplayName())
230        {
231            ((TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4)).func_94049_a(par6ItemStack.getDisplayName());
232        }
233    }
234
235    /**
236     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
237     */
238    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
239    {
240        TileEntityDispenser tileentitydispenser = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4);
241
242        if (tileentitydispenser != null)
243        {
244            for (int j1 = 0; j1 < tileentitydispenser.getSizeInventory(); ++j1)
245            {
246                ItemStack itemstack = tileentitydispenser.getStackInSlot(j1);
247
248                if (itemstack != null)
249                {
250                    float f = this.random.nextFloat() * 0.8F + 0.1F;
251                    float f1 = this.random.nextFloat() * 0.8F + 0.1F;
252                    float f2 = this.random.nextFloat() * 0.8F + 0.1F;
253
254                    while (itemstack.stackSize > 0)
255                    {
256                        int k1 = this.random.nextInt(21) + 10;
257
258                        if (k1 > itemstack.stackSize)
259                        {
260                            k1 = itemstack.stackSize;
261                        }
262
263                        itemstack.stackSize -= k1;
264                        EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage()));
265
266                        if (itemstack.hasTagCompound())
267                        {
268                            entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
269                        }
270
271                        float f3 = 0.05F;
272                        entityitem.motionX = (double)((float)this.random.nextGaussian() * f3);
273                        entityitem.motionY = (double)((float)this.random.nextGaussian() * f3 + 0.2F);
274                        entityitem.motionZ = (double)((float)this.random.nextGaussian() * f3);
275                        par1World.spawnEntityInWorld(entityitem);
276                    }
277                }
278            }
279
280            par1World.func_96440_m(par2, par3, par4, par5);
281        }
282
283        super.breakBlock(par1World, par2, par3, par4, par5, par6);
284    }
285
286    public static IPosition getIPositionFromBlockSource(IBlockSource par0IBlockSource)
287    {
288        EnumFacing enumfacing = getFacing(par0IBlockSource.getBlockMetadata());
289        double d0 = par0IBlockSource.getX() + 0.7D * (double)enumfacing.getFrontOffsetX();
290        double d1 = par0IBlockSource.getY() + 0.7D * (double)enumfacing.getFrontOffsetY();
291        double d2 = par0IBlockSource.getZ() + 0.7D * (double)enumfacing.getFrontOffsetZ();
292        return new PositionImpl(d0, d1, d2);
293    }
294
295    public static EnumFacing getFacing(int par0)
296    {
297        return EnumFacing.getFront(par0 & 7);
298    }
299
300    /**
301     * If this returns true, then comparators facing away from this block will use the value from
302     * getComparatorInputOverride instead of the actual redstone signal strength.
303     */
304    public boolean hasComparatorInputOverride()
305    {
306        return true;
307    }
308
309    /**
310     * If hasComparatorInputOverride returns true, the return value from this is used instead of the redstone signal
311     * strength when this block inputs to a comparator.
312     */
313    public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5)
314    {
315        return Container.func_94526_b((IInventory)par1World.getBlockTileEntity(par2, par3, par4));
316    }
317}