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