001    package net.minecraft.inventory;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.SideOnly;
005    import java.util.ArrayList;
006    import java.util.HashSet;
007    import java.util.List;
008    import java.util.Set;
009    import net.minecraft.entity.player.EntityPlayer;
010    import net.minecraft.entity.player.InventoryPlayer;
011    import net.minecraft.item.ItemStack;
012    
013    public 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    }