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