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        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        /**
136         * dispenses an item from a randomly selected item stack from the blocks inventory into the game world.
137         */
138        private void dispenseItem(World par1World, int par2, int par3, int par4, Random par5Random)
139        {
140            int var6 = par1World.getBlockMetadata(par2, par3, par4);
141            byte var9 = 0;
142            byte var10 = 0;
143    
144            if (var6 == 3)
145            {
146                var10 = 1;
147            }
148            else if (var6 == 2)
149            {
150                var10 = -1;
151            }
152            else if (var6 == 5)
153            {
154                var9 = 1;
155            }
156            else
157            {
158                var9 = -1;
159            }
160    
161            TileEntityDispenser var11 = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4);
162    
163            if (var11 != null)
164            {
165                int var12 = var11.getRandomStackFromInventory();
166    
167                if (var12 < 0)
168                {
169                    par1World.playAuxSFX(1001, par2, par3, par4, 0);
170                }
171                else
172                {
173                    double var13 = (double)par2 + (double)var9 * 0.6D + 0.5D;
174                    double var15 = (double)par3 + 0.5D;
175                    double var17 = (double)par4 + (double)var10 * 0.6D + 0.5D;
176                    ItemStack var19 = var11.getStackInSlot(var12);
177                    int var20 = spawnEntityWithAction(var11, par1World, var19, par5Random, par2, par3, par4, var9, var10, var13, var15, var17);
178    
179                    if (var20 == 1)
180                    {
181                        var11.decrStackSize(var12, 1);
182                    }
183                    else if (var20 == 0)
184                    {
185                        var19 = var11.decrStackSize(var12, 1);
186                        dispenseEntityFromStack(par1World, var19, par5Random, 6, var9, var10, var13, var15, var17);
187                        par1World.playAuxSFX(1000, par2, par3, par4, 0);
188                    }
189    
190                    par1World.playAuxSFX(2000, par2, par3, par4, var9 + 1 + (var10 + 1) * 3);
191                }
192            }
193        }
194    
195        /**
196         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
197         * their own) Args: x, y, z, neighbor blockID
198         */
199        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
200        {
201            if (par5 > 0 && Block.blocksList[par5].canProvidePower())
202            {
203                boolean var6 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4);
204    
205                if (var6)
206                {
207                    par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate());
208                }
209            }
210        }
211    
212        /**
213         * Ticks the block if it's been scheduled
214         */
215        public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
216        {
217            if (!par1World.isRemote && (par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4)))
218            {
219                this.dispenseItem(par1World, par2, par3, par4, par5Random);
220            }
221        }
222    
223        /**
224         * Returns a new instance of a block's tile entity class. Called on placing the block.
225         */
226        public TileEntity createNewTileEntity(World par1World)
227        {
228            return new TileEntityDispenser();
229        }
230    
231        /**
232         * Called when the block is placed in the world.
233         */
234        public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving)
235        {
236            int var6 = MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
237    
238            if (var6 == 0)
239            {
240                par1World.setBlockMetadataWithNotify(par2, par3, par4, 2);
241            }
242    
243            if (var6 == 1)
244            {
245                par1World.setBlockMetadataWithNotify(par2, par3, par4, 5);
246            }
247    
248            if (var6 == 2)
249            {
250                par1World.setBlockMetadataWithNotify(par2, par3, par4, 3);
251            }
252    
253            if (var6 == 3)
254            {
255                par1World.setBlockMetadataWithNotify(par2, par3, par4, 4);
256            }
257        }
258    
259        /**
260         * ejects contained items into the world, and notifies neighbours of an update, as appropriate
261         */
262        public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
263        {
264            TileEntityDispenser var7 = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4);
265    
266            if (var7 != null)
267            {
268                for (int var8 = 0; var8 < var7.getSizeInventory(); ++var8)
269                {
270                    ItemStack var9 = var7.getStackInSlot(var8);
271    
272                    if (var9 != null)
273                    {
274                        float var10 = this.random.nextFloat() * 0.8F + 0.1F;
275                        float var11 = this.random.nextFloat() * 0.8F + 0.1F;
276                        float var12 = this.random.nextFloat() * 0.8F + 0.1F;
277    
278                        while (var9.stackSize > 0)
279                        {
280                            int var13 = this.random.nextInt(21) + 10;
281    
282                            if (var13 > var9.stackSize)
283                            {
284                                var13 = var9.stackSize;
285                            }
286    
287                            var9.stackSize -= var13;
288                            EntityItem var14 = new EntityItem(par1World, (double)((float)par2 + var10), (double)((float)par3 + var11), (double)((float)par4 + var12), new ItemStack(var9.itemID, var13, var9.getItemDamage()));
289    
290                            if (var9.hasTagCompound())
291                            {
292                                var14.item.setTagCompound((NBTTagCompound)var9.getTagCompound().copy());
293                            }
294    
295                            float var15 = 0.05F;
296                            var14.motionX = (double)((float)this.random.nextGaussian() * var15);
297                            var14.motionY = (double)((float)this.random.nextGaussian() * var15 + 0.2F);
298                            var14.motionZ = (double)((float)this.random.nextGaussian() * var15);
299                            par1World.spawnEntityInWorld(var14);
300                        }
301                    }
302                }
303            }
304    
305            super.breakBlock(par1World, par2, par3, par4, par5, par6);
306        }
307    
308        private static void dispenseEntityFromStack(World par0World, ItemStack par1ItemStack, Random par2Random, int par3, int par4, int par5, double par6, double par8, double par10)
309        {
310            EntityItem var12 = new EntityItem(par0World, par6, par8 - 0.3D, par10, par1ItemStack);
311            double var13 = par2Random.nextDouble() * 0.1D + 0.2D;
312            var12.motionX = (double)par4 * var13;
313            var12.motionY = 0.20000000298023224D;
314            var12.motionZ = (double)par5 * var13;
315            var12.motionX += par2Random.nextGaussian() * 0.007499999832361937D * (double)par3;
316            var12.motionY += par2Random.nextGaussian() * 0.007499999832361937D * (double)par3;
317            var12.motionZ += par2Random.nextGaussian() * 0.007499999832361937D * (double)par3;
318            par0World.spawnEntityInWorld(var12);
319        }
320    
321        /**
322         * arrows are fired, eggs are thrown, buckets create liquid blocks ...
323         */
324        private static int spawnEntityWithAction(TileEntityDispenser par0TileEntityDispenser, World par1World, ItemStack par2ItemStack, Random par3Random, int par4, int par5, int par6, int par7, int par8, double par9, double par11, double par13)
325        {
326            float var15 = 1.1F;
327            byte var16 = 6;
328            int modDispense = GameRegistry.tryDispense(par1World, par4, par5, par6, par7, par8, par2ItemStack, par3Random, par9, par11, par13);
329            if (modDispense > -1)
330            {
331                return modDispense;
332            }
333            if (par2ItemStack.itemID == Item.arrow.shiftedIndex)
334            {
335                EntityArrow var28 = new EntityArrow(par1World, par9, par11, par13);
336                var28.setArrowHeading((double)par7, 0.10000000149011612D, (double)par8, var15, (float)var16);
337                var28.canBePickedUp = 1;
338                par1World.spawnEntityInWorld(var28);
339                par1World.playAuxSFX(1002, par4, par5, par6, 0);
340                return 1;
341            }
342            else if (par2ItemStack.itemID == Item.egg.shiftedIndex)
343            {
344                EntityEgg var29 = new EntityEgg(par1World, par9, par11, par13);
345                var29.setThrowableHeading((double)par7, 0.10000000149011612D, (double)par8, var15, (float)var16);
346                par1World.spawnEntityInWorld(var29);
347                par1World.playAuxSFX(1002, par4, par5, par6, 0);
348                return 1;
349            }
350            else if (par2ItemStack.itemID == Item.snowball.shiftedIndex)
351            {
352                EntitySnowball var24 = new EntitySnowball(par1World, par9, par11, par13);
353                var24.setThrowableHeading((double)par7, 0.10000000149011612D, (double)par8, var15, (float)var16);
354                par1World.spawnEntityInWorld(var24);
355                par1World.playAuxSFX(1002, par4, par5, par6, 0);
356                return 1;
357            }
358            else if (par2ItemStack.itemID == Item.potion.shiftedIndex && ItemPotion.isSplash(par2ItemStack.getItemDamage()))
359            {
360                EntityPotion var25 = new EntityPotion(par1World, par9, par11, par13, par2ItemStack.getItemDamage());
361                var25.setThrowableHeading((double)par7, 0.10000000149011612D, (double)par8, var15 * 1.25F, (float)var16 * 0.5F);
362                par1World.spawnEntityInWorld(var25);
363                par1World.playAuxSFX(1002, par4, par5, par6, 0);
364                return 1;
365            }
366            else if (par2ItemStack.itemID == Item.expBottle.shiftedIndex)
367            {
368                EntityExpBottle var26 = new EntityExpBottle(par1World, par9, par11, par13);
369                var26.setThrowableHeading((double)par7, 0.10000000149011612D, (double)par8, var15 * 1.25F, (float)var16 * 0.5F);
370                par1World.spawnEntityInWorld(var26);
371                par1World.playAuxSFX(1002, par4, par5, par6, 0);
372                return 1;
373            }
374            else if (par2ItemStack.itemID == Item.monsterPlacer.shiftedIndex)
375            {
376                ItemMonsterPlacer.spawnCreature(par1World, par2ItemStack.getItemDamage(), par9 + (double)par7 * 0.3D, par11 - 0.3D, par13 + (double)par8 * 0.3D);
377                par1World.playAuxSFX(1002, par4, par5, par6, 0);
378                return 1;
379            }
380            else if (par2ItemStack.itemID == Item.fireballCharge.shiftedIndex)
381            {
382                EntitySmallFireball var27 = new EntitySmallFireball(par1World, par9 + (double)par7 * 0.3D, par11, par13 + (double)par8 * 0.3D, (double)par7 + par3Random.nextGaussian() * 0.05D, par3Random.nextGaussian() * 0.05D, (double)par8 + par3Random.nextGaussian() * 0.05D);
383                par1World.spawnEntityInWorld(var27);
384                par1World.playAuxSFX(1009, par4, par5, par6, 0);
385                return 1;
386            }
387            else if (par2ItemStack.itemID != Item.bucketLava.shiftedIndex && par2ItemStack.itemID != Item.bucketWater.shiftedIndex)
388            {
389                if (par2ItemStack.itemID == Item.bucketEmpty.shiftedIndex)
390                {
391                    int var21 = par4 + par7;
392                    int var18 = par6 + par8;
393                    Material var19 = par1World.getBlockMaterial(var21, par5, var18);
394                    int var20 = par1World.getBlockMetadata(var21, par5, var18);
395    
396                    if (var19 == Material.water && var20 == 0)
397                    {
398                        par1World.setBlockWithNotify(var21, par5, var18, 0);
399    
400                        if (--par2ItemStack.stackSize == 0)
401                        {
402                            par2ItemStack.itemID = Item.bucketWater.shiftedIndex;
403                            par2ItemStack.stackSize = 1;
404                        }
405                        else if (par0TileEntityDispenser.func_70360_a(new ItemStack(Item.bucketWater)) < 0)
406                        {
407                            dispenseEntityFromStack(par1World, new ItemStack(Item.bucketWater), par3Random, 6, par7, par8, par9, par11, par13);
408                        }
409    
410                        return 2;
411                    }
412                    else if (var19 == Material.lava && var20 == 0)
413                    {
414                        par1World.setBlockWithNotify(var21, par5, var18, 0);
415    
416                        if (--par2ItemStack.stackSize == 0)
417                        {
418                            par2ItemStack.itemID = Item.bucketLava.shiftedIndex;
419                            par2ItemStack.stackSize = 1;
420                        }
421                        else if (par0TileEntityDispenser.func_70360_a(new ItemStack(Item.bucketLava)) < 0)
422                        {
423                            dispenseEntityFromStack(par1World, new ItemStack(Item.bucketLava), par3Random, 6, par7, par8, par9, par11, par13);
424                        }
425    
426                        return 2;
427                    }
428                    else
429                    {
430                        return 0;
431                    }
432                }
433                else if (par2ItemStack.getItem() instanceof ItemMinecart)
434                {
435                    par9 = (double)par4 + (par7 < 0 ? (double)par7 * 0.8D : (double)((float)par7 * 1.8F)) + (double)((float)Math.abs(par8) * 0.5F);
436                    par13 = (double)par6 + (par8 < 0 ? (double)par8 * 0.8D : (double)((float)par8 * 1.8F)) + (double)((float)Math.abs(par7) * 0.5F);
437    
438                    if (BlockRail.isRailBlockAt(par1World, par4 + par7, par5, par6 + par8))
439                    {
440                        par11 = (double)((float)par5 + 0.5F);
441                    }
442                    else
443                    {
444                        if (!par1World.isAirBlock(par4 + par7, par5, par6 + par8) || !BlockRail.isRailBlockAt(par1World, par4 + par7, par5 - 1, par6 + par8))
445                        {
446                            return 0;
447                        }
448    
449                        par11 = (double)((float)par5 - 0.5F);
450                    }
451    
452                    EntityMinecart var22 = new EntityMinecart(par1World, par9, par11, par13, ((ItemMinecart)par2ItemStack.getItem()).minecartType);
453                    par1World.spawnEntityInWorld(var22);
454                    par1World.playAuxSFX(1000, par4, par5, par6, 0);
455                    return 1;
456                }
457                else if (par2ItemStack.itemID == Item.boat.shiftedIndex)
458                {
459                    par9 = (double)par4 + (par7 < 0 ? (double)par7 * 0.8D : (double)((float)par7 * 1.8F)) + (double)((float)Math.abs(par8) * 0.5F);
460                    par13 = (double)par6 + (par8 < 0 ? (double)par8 * 0.8D : (double)((float)par8 * 1.8F)) + (double)((float)Math.abs(par7) * 0.5F);
461    
462                    if (par1World.getBlockMaterial(par4 + par7, par5, par6 + par8) == Material.water)
463                    {
464                        par11 = (double)((float)par5 + 1.0F);
465                    }
466                    else
467                    {
468                        if (!par1World.isAirBlock(par4 + par7, par5, par6 + par8) || par1World.getBlockMaterial(par4 + par7, par5 - 1, par6 + par8) != Material.water)
469                        {
470                            return 0;
471                        }
472    
473                        par11 = (double)par5;
474                    }
475    
476                    EntityBoat var23 = new EntityBoat(par1World, par9, par11, par13);
477                    par1World.spawnEntityInWorld(var23);
478                    par1World.playAuxSFX(1000, par4, par5, par6, 0);
479                    return 1;
480                }
481                else
482                {
483                    return 0;
484                }
485            }
486            else
487            {
488                ItemBucket var17 = (ItemBucket)par2ItemStack.getItem();
489    
490                if (var17.func_77875_a(par1World, (double)par4, (double)par5, (double)par6, par4 + par7, par5, par6 + par8))
491                {
492                    par2ItemStack.itemID = Item.bucketEmpty.shiftedIndex;
493                    par2ItemStack.stackSize = 1;
494                    return 2;
495                }
496                else
497                {
498                    return 0;
499                }
500            }
501        }
502    }