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