    001package net.minecraft.tileentity;
    002
    003import java.util.Random;
    004import net.minecraft.entity.player.EntityPlayer;
    005import net.minecraft.inventory.IInventory;
    006import net.minecraft.item.ItemStack;
    007import net.minecraft.nbt.NBTTagCompound;
    008import net.minecraft.nbt.NBTTagList;
    009
    010public class TileEntityDispenser extends TileEntity implements IInventory
    011{
    012    private ItemStack[] dispenserContents = new ItemStack[9];
    013
    014    /**
    015     * random number generator for instance. Used in random item stack selection.
    016     */
    017    private Random dispenserRandom = new Random();
    018    protected String field_94050_c;
    019
    020    /**
    021     * Returns the number of slots in the inventory.
    022     */
    023    public int getSizeInventory()
    024    {
    025        return 9;
    026    }
    027
    028    /**
    029     * Returns the stack in slot i
    030     */
    031    public ItemStack getStackInSlot(int par1)
    032    {
    033        return this.dispenserContents[par1];
    034    }
    035
    036    /**
    037     * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
    038     * new stack.
    039     */
    040    public ItemStack decrStackSize(int par1, int par2)
    041    {
    042        if (this.dispenserContents[par1] != null)
    043        {
    044            ItemStack itemstack;
    045
    046            if (this.dispenserContents[par1].stackSize <= par2)
    047            {
    048                itemstack = this.dispenserContents[par1];
    049                this.dispenserContents[par1] = null;
    050                this.onInventoryChanged();
    051                return itemstack;
    052            }
    053            else
    054            {
    055                itemstack = this.dispenserContents[par1].splitStack(par2);
    056
    057                if (this.dispenserContents[par1].stackSize == 0)
    058                {
    059                    this.dispenserContents[par1] = null;
    060                }
    061
    062                this.onInventoryChanged();
    063                return itemstack;
    064            }
    065        }
    066        else
    067        {
    068            return null;
    069        }
    070    }
    071
    072    /**
    073     * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
    074     * like when you close a workbench GUI.
    075     */
    076    public ItemStack getStackInSlotOnClosing(int par1)
    077    {
    078        if (this.dispenserContents[par1] != null)
    079        {
    080            ItemStack itemstack = this.dispenserContents[par1];
    081            this.dispenserContents[par1] = null;
    082            return itemstack;
    083        }
    084        else
    085        {
    086            return null;
    087        }
    088    }
    089
    090    public int getRandomStackFromInventory()
    091    {
    092        int i = -1;
    093        int j = 1;
    094
    095        for (int k = 0; k < this.dispenserContents.length; ++k)
    096        {
    097            if (this.dispenserContents[k] != null && this.dispenserRandom.nextInt(j++) == 0)
    098            {
    099                i = k;
    100            }
    101        }
    102
    103        return i;
    104    }
    105
    106    /**
    107     * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
    108     */
    109    public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
    110    {
    111        this.dispenserContents[par1] = par2ItemStack;
    112
    113        if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
    114        {
    115            par2ItemStack.stackSize = this.getInventoryStackLimit();
    116        }
    117
    118        this.onInventoryChanged();
    119    }
    120
    121    /**
    122     * Add item stack in first available inventory slot
    123     */
    124    public int addItem(ItemStack par1ItemStack)
    125    {
    126        for (int i = 0; i < this.dispenserContents.length; ++i)
    127        {
    128            if (this.dispenserContents[i] == null || this.dispenserContents[i].itemID == 0)
    129            {
    130                this.setInventorySlotContents(i, par1ItemStack);
    131                return i;
    132            }
    133        }
    134
    135        return -1;
    136    }
    137
    138    /**
    139     * Returns the name of the inventory.
    140     */
    141    public String getInvName()
    142    {
    143        return this.isInvNameLocalized() ? this.field_94050_c : "container.dispenser";
    144    }
    145
    146    public void func_94049_a(String par1Str)
    147    {
    148        this.field_94050_c = par1Str;
    149    }
    150
    151    /**
    152     * If this returns false, the inventory name will be used as an unlocalized name, and translated into the player's
    153     * language. Otherwise it will be used directly.
    154     */
    155    public boolean isInvNameLocalized()
    156    {
    157        return this.field_94050_c != null;
    158    }
    159
    160    /**
    161     * Reads a tile entity from NBT.
    162     */
    163    public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    164    {
    165        super.readFromNBT(par1NBTTagCompound);
    166        NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items");
    167        this.dispenserContents = new ItemStack[this.getSizeInventory()];
    168
    169        for (int i = 0; i < nbttaglist.tagCount(); ++i)
    170        {
    171            NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
    172            int j = nbttagcompound1.getByte("Slot") & 255;
    173
    174            if (j >= 0 && j < this.dispenserContents.length)
    175            {
    176                this.dispenserContents[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
    177            }
    178        }
    179
    180        if (par1NBTTagCompound.hasKey("CustomName"))
    181        {
    182            this.field_94050_c = par1NBTTagCompound.getString("CustomName");
    183        }
    184    }
    185
    186    /**
    187     * Writes a tile entity to NBT.
    188     */
    189    public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    190    {
    191        super.writeToNBT(par1NBTTagCompound);
    192        NBTTagList nbttaglist = new NBTTagList();
    193
    194        for (int i = 0; i < this.dispenserContents.length; ++i)
    195        {
    196            if (this.dispenserContents[i] != null)
    197            {
    198                NBTTagCompound nbttagcompound1 = new NBTTagCompound();
    199                nbttagcompound1.setByte("Slot", (byte)i);
    200                this.dispenserContents[i].writeToNBT(nbttagcompound1);
    201                nbttaglist.appendTag(nbttagcompound1);
    202            }
    203        }
    204
    205        par1NBTTagCompound.setTag("Items", nbttaglist);
    206
    207        if (this.isInvNameLocalized())
    208        {
    209            par1NBTTagCompound.setString("CustomName", this.field_94050_c);
    210        }
    211    }
    212
    213    /**
    214     * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
    215     * this more of a set than a get?*
    216     */
    217    public int getInventoryStackLimit()
    218    {
    219        return 64;
    220    }
    221
    222    /**
    223     * Do not make give this method the name canInteractWith because it clashes with Container
    224     */
    225    public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
    226    {
    227        return this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) <= 64.0D;
    228    }
    229
    230    public void openChest() {}
    231
    232    public void closeChest() {}
    233
    234    /**
    235     * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot.
    236     */
    237    public boolean isStackValidForSlot(int par1, ItemStack par2ItemStack)
    238    {
    239        return true;
    240    }
    241}