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 }