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