    001    package net.minecraft.block;
    002
    003    import cpw.mods.fml.common.Side;
    004    import cpw.mods.fml.common.asm.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.item.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    }