001 package net.minecraft.src;
002
003 import java.util.Iterator;
004 import java.util.List;
005
006 public class TileEntityChest extends TileEntity implements IInventory
007 {
008 private ItemStack[] chestContents = new ItemStack[36];
009
010 /** Determines if the check for adjacent chests has taken place. */
011 public boolean adjacentChestChecked = false;
012
013 /** Contains the chest tile located adjacent to this one (if any) */
014 public TileEntityChest adjacentChestZNeg;
015
016 /** Contains the chest tile located adjacent to this one (if any) */
017 public TileEntityChest adjacentChestXPos;
018
019 /** Contains the chest tile located adjacent to this one (if any) */
020 public TileEntityChest adjacentChestXNeg;
021
022 /** Contains the chest tile located adjacent to this one (if any) */
023 public TileEntityChest adjacentChestZPosition;
024
025 /** The current angle of the lid (between 0 and 1) */
026 public float lidAngle;
027
028 /** The angle of the lid last tick */
029 public float prevLidAngle;
030
031 /** The number of players currently using this chest */
032 public int numUsingPlayers;
033
034 /** Server sync counter (once per 20 ticks) */
035 private int ticksSinceSync;
036
037 /**
038 * Returns the number of slots in the inventory.
039 */
040 public int getSizeInventory()
041 {
042 return 27;
043 }
044
045 /**
046 * Returns the stack in slot i
047 */
048 public ItemStack getStackInSlot(int par1)
049 {
050 return this.chestContents[par1];
051 }
052
053 /**
054 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
055 * new stack.
056 */
057 public ItemStack decrStackSize(int par1, int par2)
058 {
059 if (this.chestContents[par1] != null)
060 {
061 ItemStack var3;
062
063 if (this.chestContents[par1].stackSize <= par2)
064 {
065 var3 = this.chestContents[par1];
066 this.chestContents[par1] = null;
067 this.onInventoryChanged();
068 return var3;
069 }
070 else
071 {
072 var3 = this.chestContents[par1].splitStack(par2);
073
074 if (this.chestContents[par1].stackSize == 0)
075 {
076 this.chestContents[par1] = null;
077 }
078
079 this.onInventoryChanged();
080 return var3;
081 }
082 }
083 else
084 {
085 return null;
086 }
087 }
088
089 /**
090 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
091 * like when you close a workbench GUI.
092 */
093 public ItemStack getStackInSlotOnClosing(int par1)
094 {
095 if (this.chestContents[par1] != null)
096 {
097 ItemStack var2 = this.chestContents[par1];
098 this.chestContents[par1] = null;
099 return var2;
100 }
101 else
102 {
103 return null;
104 }
105 }
106
107 /**
108 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
109 */
110 public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
111 {
112 this.chestContents[par1] = par2ItemStack;
113
114 if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
115 {
116 par2ItemStack.stackSize = this.getInventoryStackLimit();
117 }
118
119 this.onInventoryChanged();
120 }
121
122 /**
123 * Returns the name of the inventory.
124 */
125 public String getInvName()
126 {
127 return "container.chest";
128 }
129
130 /**
131 * Reads a tile entity from NBT.
132 */
133 public void readFromNBT(NBTTagCompound par1NBTTagCompound)
134 {
135 super.readFromNBT(par1NBTTagCompound);
136 NBTTagList var2 = par1NBTTagCompound.getTagList("Items");
137 this.chestContents = new ItemStack[this.getSizeInventory()];
138
139 for (int var3 = 0; var3 < var2.tagCount(); ++var3)
140 {
141 NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
142 int var5 = var4.getByte("Slot") & 255;
143
144 if (var5 >= 0 && var5 < this.chestContents.length)
145 {
146 this.chestContents[var5] = ItemStack.loadItemStackFromNBT(var4);
147 }
148 }
149 }
150
151 /**
152 * Writes a tile entity to NBT.
153 */
154 public void writeToNBT(NBTTagCompound par1NBTTagCompound)
155 {
156 super.writeToNBT(par1NBTTagCompound);
157 NBTTagList var2 = new NBTTagList();
158
159 for (int var3 = 0; var3 < this.chestContents.length; ++var3)
160 {
161 if (this.chestContents[var3] != null)
162 {
163 NBTTagCompound var4 = new NBTTagCompound();
164 var4.setByte("Slot", (byte)var3);
165 this.chestContents[var3].writeToNBT(var4);
166 var2.appendTag(var4);
167 }
168 }
169
170 par1NBTTagCompound.setTag("Items", var2);
171 }
172
173 /**
174 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
175 * this more of a set than a get?*
176 */
177 public int getInventoryStackLimit()
178 {
179 return 64;
180 }
181
182 /**
183 * Do not make give this method the name canInteractWith because it clashes with Container
184 */
185 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
186 {
187 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;
188 }
189
190 /**
191 * Causes the TileEntity to reset all it's cached values for it's container block, blockID, metaData and in the case
192 * of chests, the adjcacent chest check
193 */
194 public void updateContainingBlockInfo()
195 {
196 super.updateContainingBlockInfo();
197 this.adjacentChestChecked = false;
198 }
199
200 private void func_90009_a(TileEntityChest par1TileEntityChest, int par2)
201 {
202 if (par1TileEntityChest.isInvalid())
203 {
204 this.adjacentChestChecked = false;
205 }
206 else if (this.adjacentChestChecked)
207 {
208 switch (par2)
209 {
210 case 0:
211 if (this.adjacentChestZPosition != par1TileEntityChest)
212 {
213 this.adjacentChestChecked = false;
214 }
215
216 break;
217 case 1:
218 if (this.adjacentChestXNeg != par1TileEntityChest)
219 {
220 this.adjacentChestChecked = false;
221 }
222
223 break;
224 case 2:
225 if (this.adjacentChestZNeg != par1TileEntityChest)
226 {
227 this.adjacentChestChecked = false;
228 }
229
230 break;
231 case 3:
232 if (this.adjacentChestXPos != par1TileEntityChest)
233 {
234 this.adjacentChestChecked = false;
235 }
236 }
237 }
238 }
239
240 /**
241 * Performs the check for adjacent chests to determine if this chest is double or not.
242 */
243 public void checkForAdjacentChests()
244 {
245 if (!this.adjacentChestChecked)
246 {
247 this.adjacentChestChecked = true;
248 this.adjacentChestZNeg = null;
249 this.adjacentChestXPos = null;
250 this.adjacentChestXNeg = null;
251 this.adjacentChestZPosition = null;
252
253 if (this.worldObj.getBlockId(this.xCoord - 1, this.yCoord, this.zCoord) == Block.chest.blockID)
254 {
255 this.adjacentChestXNeg = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord - 1, this.yCoord, this.zCoord);
256 }
257
258 if (this.worldObj.getBlockId(this.xCoord + 1, this.yCoord, this.zCoord) == Block.chest.blockID)
259 {
260 this.adjacentChestXPos = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord + 1, this.yCoord, this.zCoord);
261 }
262
263 if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord - 1) == Block.chest.blockID)
264 {
265 this.adjacentChestZNeg = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord - 1);
266 }
267
268 if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord + 1) == Block.chest.blockID)
269 {
270 this.adjacentChestZPosition = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord + 1);
271 }
272
273 if (this.adjacentChestZNeg != null)
274 {
275 this.adjacentChestZNeg.func_90009_a(this, 0);
276 }
277
278 if (this.adjacentChestZPosition != null)
279 {
280 this.adjacentChestZPosition.func_90009_a(this, 2);
281 }
282
283 if (this.adjacentChestXPos != null)
284 {
285 this.adjacentChestXPos.func_90009_a(this, 1);
286 }
287
288 if (this.adjacentChestXNeg != null)
289 {
290 this.adjacentChestXNeg.func_90009_a(this, 3);
291 }
292 }
293 }
294
295 /**
296 * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
297 * ticks and creates a new spawn inside its implementation.
298 */
299 public void updateEntity()
300 {
301 super.updateEntity();
302 this.checkForAdjacentChests();
303 ++this.ticksSinceSync;
304 float var1;
305
306 if (!this.worldObj.isRemote && this.numUsingPlayers != 0 && (this.ticksSinceSync + this.xCoord + this.yCoord + this.zCoord) % 200 == 0)
307 {
308 this.numUsingPlayers = 0;
309 var1 = 5.0F;
310 List var2 = this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)((float)this.xCoord - var1), (double)((float)this.yCoord - var1), (double)((float)this.zCoord - var1), (double)((float)(this.xCoord + 1) + var1), (double)((float)(this.yCoord + 1) + var1), (double)((float)(this.zCoord + 1) + var1)));
311 Iterator var3 = var2.iterator();
312
313 while (var3.hasNext())
314 {
315 EntityPlayer var4 = (EntityPlayer)var3.next();
316
317 if (var4.craftingInventory instanceof ContainerChest)
318 {
319 IInventory var5 = ((ContainerChest)var4.craftingInventory).func_85151_d();
320
321 if (var5 == this || var5 instanceof InventoryLargeChest && ((InventoryLargeChest)var5).func_90010_a(this))
322 {
323 ++this.numUsingPlayers;
324 }
325 }
326 }
327 }
328
329 this.prevLidAngle = this.lidAngle;
330 var1 = 0.1F;
331 double var11;
332
333 if (this.numUsingPlayers > 0 && this.lidAngle == 0.0F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
334 {
335 double var8 = (double)this.xCoord + 0.5D;
336 var11 = (double)this.zCoord + 0.5D;
337
338 if (this.adjacentChestZPosition != null)
339 {
340 var11 += 0.5D;
341 }
342
343 if (this.adjacentChestXPos != null)
344 {
345 var8 += 0.5D;
346 }
347
348 this.worldObj.playSoundEffect(var8, (double)this.yCoord + 0.5D, var11, "random.chestopen", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
349 }
350
351 if (this.numUsingPlayers == 0 && this.lidAngle > 0.0F || this.numUsingPlayers > 0 && this.lidAngle < 1.0F)
352 {
353 float var9 = this.lidAngle;
354
355 if (this.numUsingPlayers > 0)
356 {
357 this.lidAngle += var1;
358 }
359 else
360 {
361 this.lidAngle -= var1;
362 }
363
364 if (this.lidAngle > 1.0F)
365 {
366 this.lidAngle = 1.0F;
367 }
368
369 float var10 = 0.5F;
370
371 if (this.lidAngle < var10 && var9 >= var10 && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
372 {
373 var11 = (double)this.xCoord + 0.5D;
374 double var6 = (double)this.zCoord + 0.5D;
375
376 if (this.adjacentChestZPosition != null)
377 {
378 var6 += 0.5D;
379 }
380
381 if (this.adjacentChestXPos != null)
382 {
383 var11 += 0.5D;
384 }
385
386 this.worldObj.playSoundEffect(var11, (double)this.yCoord + 0.5D, var6, "random.chestclosed", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
387 }
388
389 if (this.lidAngle < 0.0F)
390 {
391 this.lidAngle = 0.0F;
392 }
393 }
394 }
395
396 /**
397 * Called when a client event is received with the event number and argument, see World.sendClientEvent
398 */
399 public void receiveClientEvent(int par1, int par2)
400 {
401 if (par1 == 1)
402 {
403 this.numUsingPlayers = par2;
404 }
405 }
406
407 public void openChest()
408 {
409 ++this.numUsingPlayers;
410 this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, Block.chest.blockID, 1, this.numUsingPlayers);
411 }
412
413 public void closeChest()
414 {
415 --this.numUsingPlayers;
416 this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, Block.chest.blockID, 1, this.numUsingPlayers);
417 }
418
419 /**
420 * invalidates a tile entity
421 */
422 public void invalidate()
423 {
424 super.invalidate();
425 this.updateContainingBlockInfo();
426 this.checkForAdjacentChests();
427 }
428 }