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