    001package net.minecraft.inventory;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.ArrayList;
    006import java.util.HashSet;
    007import java.util.List;
    008import java.util.Set;
    009import net.minecraft.entity.player.EntityPlayer;
    010import net.minecraft.entity.player.InventoryPlayer;
    011import net.minecraft.item.ItemStack;
    012
    013public abstract class Container
    014{
    015    /** the list of all items(stacks) for the corresponding slot */
    016    public List inventoryItemStacks = new ArrayList();
    017
    018    /** the list of all slots in the inventory */
    019    public List inventorySlots = new ArrayList();
    020    public int windowId = 0;
    021    private short transactionID = 0;
    022
    023    /**
    024     * list of all people that need to be notified when this craftinventory changes
    025     */
    026    protected List crafters = new ArrayList();
    027    private Set playerList = new HashSet();
    028
    029    /**
    030     * the slot is assumed empty
    031     */
    032    protected Slot addSlotToContainer(Slot par1Slot)
    033    {
    034        par1Slot.slotNumber = this.inventorySlots.size();
    035        this.inventorySlots.add(par1Slot);
    036        this.inventoryItemStacks.add((Object)null);
    037        return par1Slot;
    038    }
    039
    040    public void addCraftingToCrafters(ICrafting par1ICrafting)
    041    {
    042        if (this.crafters.contains(par1ICrafting))
    043        {
    044            throw new IllegalArgumentException("Listener already listening");
    045        }
    046        else
    047        {
    048            this.crafters.add(par1ICrafting);
    049            par1ICrafting.sendContainerAndContentsToPlayer(this, this.getInventory());
    050            this.detectAndSendChanges();
    051        }
    052    }
    053
    054    /**
    055     * returns a list if itemStacks, for each slot.
    056     */
    057    public List getInventory()
    058    {
    059        ArrayList var1 = new ArrayList();
    060
    061        for (int var2 = 0; var2 < this.inventorySlots.size(); ++var2)
    062        {
    063            var1.add(((Slot)this.inventorySlots.get(var2)).getStack());
    064        }
    065
    066        return var1;
    067    }
    068
    069    @SideOnly(Side.CLIENT)
    070
    071    /**
    072     * Remove this crafting listener from the listener list.
    073     */
    074    public void removeCraftingFromCrafters(ICrafting par1ICrafting)
    075    {
    076        this.crafters.remove(par1ICrafting);
    077    }
    078
    079    /**
    080     * Looks for changes made in the container, sends them to every listener.
    081     */
    082    public void detectAndSendChanges()
    083    {
    084        for (int var1 = 0; var1 < this.inventorySlots.size(); ++var1)
    085        {
    086            ItemStack var2 = ((Slot)this.inventorySlots.get(var1)).getStack();
    087            ItemStack var3 = (ItemStack)this.inventoryItemStacks.get(var1);
    088
    089            if (!ItemStack.areItemStacksEqual(var3, var2))
    090            {
    091                var3 = var2 == null ? null : var2.copy();
    092                this.inventoryItemStacks.set(var1, var3);
    093
    094                for (int var4 = 0; var4 < this.crafters.size(); ++var4)
    095                {
    096                    ((ICrafting)this.crafters.get(var4)).sendSlotContents(this, var1, var3);
    097                }
    098            }
    099        }
    100    }
    101
    102    /**
    103     * enchants the item on the table using the specified slot; also deducts XP from player
    104     */
    105    public boolean enchantItem(EntityPlayer par1EntityPlayer, int par2)
    106    {
    107        return false;
    108    }
    109
    110    public Slot getSlotFromInventory(IInventory par1IInventory, int par2)
    111    {
    112        for (int var3 = 0; var3 < this.inventorySlots.size(); ++var3)
    113        {
    114            Slot var4 = (Slot)this.inventorySlots.get(var3);
    115
    116            if (var4.isSlotInInventory(par1IInventory, par2))
    117            {
    118                return var4;
    119            }
    120        }
    121
    122        return null;
    123    }
    124
    125    public Slot getSlot(int par1)
    126    {
    127        return (Slot)this.inventorySlots.get(par1);
    128    }
    129
    130    /**
    131     * Called when a player shift-clicks on a slot. You must override this or you will crash when someone does that.
    132     */
    133    public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2)
    134    {
    135        Slot var3 = (Slot)this.inventorySlots.get(par2);
    136        return var3 != null ? var3.getStack() : null;
    137    }
    138
    139    public ItemStack slotClick(int par1, int par2, int par3, EntityPlayer par4EntityPlayer)
    140    {
    141        ItemStack var5 = null;
    142        InventoryPlayer var6 = par4EntityPlayer.inventory;
    143        Slot var7;
    144        ItemStack var8;
    145        int var10;
    146        ItemStack var11;
    147
    148        if ((par3 == 0 || par3 == 1) && (par2 == 0 || par2 == 1))
    149        {
    150            if (par1 == -999)
    151            {
    152                if (var6.getItemStack() != null && par1 == -999)
    153                {
    154                    if (par2 == 0)
    155                    {
    156                        par4EntityPlayer.dropPlayerItem(var6.getItemStack());
    157                        var6.setItemStack((ItemStack)null);
    158                    }
    159
    160                    if (par2 == 1)
    161                    {
    162                        par4EntityPlayer.dropPlayerItem(var6.getItemStack().splitStack(1));
    163
    164                        if (var6.getItemStack().stackSize == 0)
    165                        {
    166                            var6.setItemStack((ItemStack)null);
    167                        }
    168                    }
    169                }
    170            }
    171            else if (par3 == 1)
    172            {
    173                var7 = (Slot)this.inventorySlots.get(par1);
    174
    175                if (var7 != null && var7.canTakeStack(par4EntityPlayer))
    176                {
    177                    var8 = this.transferStackInSlot(par4EntityPlayer, par1);
    178
    179                    if (var8 != null)
    180                    {
    181                        int var12 = var8.itemID;
    182                        var5 = var8.copy();
    183
    184                        if (var7 != null && var7.getStack() != null && var7.getStack().itemID == var12)
    185                        {
    186                            this.retrySlotClick(par1, par2, true, par4EntityPlayer);
    187                        }
    188                    }
    189                }
    190            }
    191            else
    192            {
    193                if (par1 < 0)
    194                {
    195                    return null;
    196                }
    197
    198                var7 = (Slot)this.inventorySlots.get(par1);
    199
    200                if (var7 != null)
    201                {
    202                    var8 = var7.getStack();
    203                    ItemStack var13 = var6.getItemStack();
    204
    205                    if (var8 != null)
    206                    {
    207                        var5 = var8.copy();
    208                    }
    209
    210                    if (var8 == null)
    211                    {
    212                        if (var13 != null && var7.isItemValid(var13))
    213                        {
    214                            var10 = par2 == 0 ? var13.stackSize : 1;
    215
    216                            if (var10 > var7.getSlotStackLimit())
    217                            {
    218                                var10 = var7.getSlotStackLimit();
    219                            }
    220
    221                            var7.putStack(var13.splitStack(var10));
    222
    223                            if (var13.stackSize == 0)
    224                            {
    225                                var6.setItemStack((ItemStack)null);
    226                            }
    227                        }
    228                    }
    229                    else if (var7.canTakeStack(par4EntityPlayer))
    230                    {
    231                        if (var13 == null)
    232                        {
    233                            var10 = par2 == 0 ? var8.stackSize : (var8.stackSize + 1) / 2;
    234                            var11 = var7.decrStackSize(var10);
    235                            var6.setItemStack(var11);
    236
    237                            if (var8.stackSize == 0)
    238                            {
    239                                var7.putStack((ItemStack)null);
    240                            }
    241
    242                            var7.onPickupFromSlot(par4EntityPlayer, var6.getItemStack());
    243                        }
    244                        else if (var7.isItemValid(var13))
    245                        {
    246                            if (var8.itemID == var13.itemID && var8.getItemDamage() == var13.getItemDamage() && ItemStack.areItemStackTagsEqual(var8, var13))
    247                            {
    248                                var10 = par2 == 0 ? var13.stackSize : 1;
    249
    250                                if (var10 > var7.getSlotStackLimit() - var8.stackSize)
    251                                {
    252                                    var10 = var7.getSlotStackLimit() - var8.stackSize;
    253                                }
    254
    255                                if (var10 > var13.getMaxStackSize() - var8.stackSize)
    256                                {
    257                                    var10 = var13.getMaxStackSize() - var8.stackSize;
    258                                }
    259
    260                                var13.splitStack(var10);
    261
    262                                if (var13.stackSize == 0)
    263                                {
    264                                    var6.setItemStack((ItemStack)null);
    265                                }
    266
    267                                var8.stackSize += var10;
    268                            }
    269                            else if (var13.stackSize <= var7.getSlotStackLimit())
    270                            {
    271                                var7.putStack(var13);
    272                                var6.setItemStack(var8);
    273                            }
    274                        }
    275                        else if (var8.itemID == var13.itemID && var13.getMaxStackSize() > 1 && (!var8.getHasSubtypes() || var8.getItemDamage() == var13.getItemDamage()) && ItemStack.areItemStackTagsEqual(var8, var13))
    276                        {
    277                            var10 = var8.stackSize;
    278
    279                            if (var10 > 0 && var10 + var13.stackSize <= var13.getMaxStackSize())
    280                            {
    281                                var13.stackSize += var10;
    282                                var8 = var7.decrStackSize(var10);
    283
    284                                if (var8.stackSize == 0)
    285                                {
    286                                    var7.putStack((ItemStack)null);
    287                                }
    288
    289                                var7.onPickupFromSlot(par4EntityPlayer, var6.getItemStack());
    290                            }
    291                        }
    292                    }
    293
    294                    var7.onSlotChanged();
    295                }
    296            }
    297        }
    298        else if (par3 == 2 && par2 >= 0 && par2 < 9)
    299        {
    300            var7 = (Slot)this.inventorySlots.get(par1);
    301
    302            if (var7.canTakeStack(par4EntityPlayer))
    303            {
    304                var8 = var6.getStackInSlot(par2);
    305                boolean var9 = var8 == null || var7.inventory == var6 && var7.isItemValid(var8);
    306                var10 = -1;
    307
    308                if (!var9)
    309                {
    310                    var10 = var6.getFirstEmptyStack();
    311                    var9 |= var10 > -1;
    312                }
    313
    314                if (var7.getHasStack() && var9)
    315                {
    316                    var11 = var7.getStack();
    317                    var6.setInventorySlotContents(par2, var11);
    318
    319                    if ((var7.inventory != var6 || !var7.isItemValid(var8)) && var8 != null)
    320                    {
    321                        if (var10 > -1)
    322                        {
    323                            var6.addItemStackToInventory(var8);
    324                            var7.decrStackSize(var11.stackSize);
    325                            var7.putStack((ItemStack)null);
    326                            var7.onPickupFromSlot(par4EntityPlayer, var11);
    327                        }
    328                    }
    329                    else
    330                    {
    331                        var7.decrStackSize(var11.stackSize);
    332                        var7.putStack(var8);
    333                        var7.onPickupFromSlot(par4EntityPlayer, var11);
    334                    }
    335                }
    336                else if (!var7.getHasStack() && var8 != null && var7.isItemValid(var8))
    337                {
    338                    var6.setInventorySlotContents(par2, (ItemStack)null);
    339                    var7.putStack(var8);
    340                }
    341            }
    342        }
    343        else if (par3 == 3 && par4EntityPlayer.capabilities.isCreativeMode && var6.getItemStack() == null && par1 >= 0)
    344        {
    345            var7 = (Slot)this.inventorySlots.get(par1);
    346
    347            if (var7 != null && var7.getHasStack())
    348            {
    349                var8 = var7.getStack().copy();
    350                var8.stackSize = var8.getMaxStackSize();
    351                var6.setItemStack(var8);
    352            }
    353        }
    354
    355        return var5;
    356    }
    357
    358    protected void retrySlotClick(int par1, int par2, boolean par3, EntityPlayer par4EntityPlayer)
    359    {
    360        this.slotClick(par1, par2, 1, par4EntityPlayer);
    361    }
    362
    363    /**
    364     * Callback for when the crafting gui is closed.
    365     */
    366    public void onCraftGuiClosed(EntityPlayer par1EntityPlayer)
    367    {
    368        InventoryPlayer var2 = par1EntityPlayer.inventory;
    369
    370        if (var2.getItemStack() != null)
    371        {
    372            par1EntityPlayer.dropPlayerItem(var2.getItemStack());
    373            var2.setItemStack((ItemStack)null);
    374        }
    375    }
    376
    377    /**
    378     * Callback for when the crafting matrix is changed.
    379     */
    380    public void onCraftMatrixChanged(IInventory par1IInventory)
    381    {
    382        this.detectAndSendChanges();
    383    }
    384
    385    /**
    386     * args: slotID, itemStack to put in slot
    387     */
    388    public void putStackInSlot(int par1, ItemStack par2ItemStack)
    389    {
    390        this.getSlot(par1).putStack(par2ItemStack);
    391    }
    392
    393    @SideOnly(Side.CLIENT)
    394
    395    /**
    396     * places itemstacks in first x slots, x being aitemstack.lenght
    397     */
    398    public void putStacksInSlots(ItemStack[] par1ArrayOfItemStack)
    399    {
    400        for (int var2 = 0; var2 < par1ArrayOfItemStack.length; ++var2)
    401        {
    402            this.getSlot(var2).putStack(par1ArrayOfItemStack[var2]);
    403        }
    404    }
    405
    406    @SideOnly(Side.CLIENT)
    407    public void updateProgressBar(int par1, int par2) {}
    408
    409    @SideOnly(Side.CLIENT)
    410
    411    /**
    412     * Gets a unique transaction ID. Parameter is unused.
    413     */
    414    public short getNextTransactionID(InventoryPlayer par1InventoryPlayer)
    415    {
    416        ++this.transactionID;
    417        return this.transactionID;
    418    }
    419
    420    /**
    421     * NotUsing because adding a player twice is an error
    422     */
    423    public boolean isPlayerNotUsingContainer(EntityPlayer par1EntityPlayer)
    424    {
    425        return !this.playerList.contains(par1EntityPlayer);
    426    }
    427
    428    /**
    429     * adds or removes the player from the container based on par2
    430     */
    431    public void setPlayerIsPresent(EntityPlayer par1EntityPlayer, boolean par2)
    432    {
    433        if (par2)
    434        {
    435            this.playerList.remove(par1EntityPlayer);
    436        }
    437        else
    438        {
    439            this.playerList.add(par1EntityPlayer);
    440        }
    441    }
    442
    443    public abstract boolean canInteractWith(EntityPlayer var1);
    444
    445    /**
    446     * merges provided ItemStack with the first avaliable one in the container/player inventory
    447     */
    448    protected boolean mergeItemStack(ItemStack par1ItemStack, int par2, int par3, boolean par4)
    449    {
    450        boolean var5 = false;
    451        int var6 = par2;
    452
    453        if (par4)
    454        {
    455            var6 = par3 - 1;
    456        }
    457
    458        Slot var7;
    459        ItemStack var8;
    460
    461        if (par1ItemStack.isStackable())
    462        {
    463            while (par1ItemStack.stackSize > 0 && (!par4 && var6 < par3 || par4 && var6 >= par2))
    464            {
    465                var7 = (Slot)this.inventorySlots.get(var6);
    466                var8 = var7.getStack();
    467
    468                if (var8 != null && var8.itemID == par1ItemStack.itemID && (!par1ItemStack.getHasSubtypes() || par1ItemStack.getItemDamage() == var8.getItemDamage()) && ItemStack.areItemStackTagsEqual(par1ItemStack, var8))
    469                {
    470                    int var9 = var8.stackSize + par1ItemStack.stackSize;
    471
    472                    if (var9 <= par1ItemStack.getMaxStackSize())
    473                    {
    474                        par1ItemStack.stackSize = 0;
    475                        var8.stackSize = var9;
    476                        var7.onSlotChanged();
    477                        var5 = true;
    478                    }
    479                    else if (var8.stackSize < par1ItemStack.getMaxStackSize())
    480                    {
    481                        par1ItemStack.stackSize -= par1ItemStack.getMaxStackSize() - var8.stackSize;
    482                        var8.stackSize = par1ItemStack.getMaxStackSize();
    483                        var7.onSlotChanged();
    484                        var5 = true;
    485                    }
    486                }
    487
    488                if (par4)
    489                {
    490                    --var6;
    491                }
    492                else
    493                {
    494                    ++var6;
    495                }
    496            }
    497        }
    498
    499        if (par1ItemStack.stackSize > 0)
    500        {
    501            if (par4)
    502            {
    503                var6 = par3 - 1;
    504            }
    505            else
    506            {
    507                var6 = par2;
    508            }
    509
    510            while (!par4 && var6 < par3 || par4 && var6 >= par2)
    511            {
    512                var7 = (Slot)this.inventorySlots.get(var6);
    513                var8 = var7.getStack();
    514
    515                if (var8 == null)
    516                {
    517                    var7.putStack(par1ItemStack.copy());
    518                    var7.onSlotChanged();
    519                    par1ItemStack.stackSize = 0;
    520                    var5 = true;
    521                    break;
    522                }
    523
    524                if (par4)
    525                {
    526                    --var6;
    527                }
    528                else
    529                {
    530                    ++var6;
    531                }
    532            }
    533        }
    534
    535        return var5;
    536    }
    537}