001    package net.minecraft.block;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.SideOnly;
005    import java.util.Random;
006    import net.minecraft.block.material.Material;
007    import net.minecraft.creativetab.CreativeTabs;
008    import net.minecraft.dispenser.BehaviorDefaultDispenseItem;
009    import net.minecraft.dispenser.IBehaviorDispenseItem;
010    import net.minecraft.dispenser.IBlockSource;
011    import net.minecraft.dispenser.IPosition;
012    import net.minecraft.dispenser.IRegistry;
013    import net.minecraft.dispenser.PositionImpl;
014    import net.minecraft.dispenser.RegistryDefaulted;
015    import net.minecraft.entity.EntityLiving;
016    import net.minecraft.entity.item.EntityItem;
017    import net.minecraft.entity.player.EntityPlayer;
018    import net.minecraft.item.ItemStack;
019    import net.minecraft.nbt.NBTTagCompound;
020    import net.minecraft.tileentity.TileEntity;
021    import net.minecraft.tileentity.TileEntityDispenser;
022    import net.minecraft.util.EnumFacing;
023    import net.minecraft.util.MathHelper;
024    import net.minecraft.world.IBlockAccess;
025    import net.minecraft.world.World;
026    
027    public 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.func_92014_d().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.func_82600_a(par0IBlockSource.func_82620_h());
298            double var2 = par0IBlockSource.getX() + 0.7D * (double)var1.func_82601_c();
299            double var4 = par0IBlockSource.getY();
300            double var6 = par0IBlockSource.getZ() + 0.7D * (double)var1.func_82599_e();
301            return new PositionImpl(var2, var4, var6);
302        }
303    }