001 package net.minecraft.src;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.SideOnly;
005 import java.util.Iterator;
006 import java.util.Random;
007 import static net.minecraftforge.common.ForgeDirection.*;
008
009 public class BlockChest extends BlockContainer
010 {
011 private Random random = new Random();
012
013 protected BlockChest(int par1)
014 {
015 super(par1, Material.wood);
016 this.blockIndexInTexture = 26;
017 this.setCreativeTab(CreativeTabs.tabDecorations);
018 this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 0.9375F, 0.875F, 0.9375F);
019 }
020
021 /**
022 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
023 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
024 */
025 public boolean isOpaqueCube()
026 {
027 return false;
028 }
029
030 /**
031 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
032 */
033 public boolean renderAsNormalBlock()
034 {
035 return false;
036 }
037
038 /**
039 * The type of render function that is called for this block
040 */
041 public int getRenderType()
042 {
043 return 22;
044 }
045
046 /**
047 * Updates the blocks bounds based on its current state. Args: world, x, y, z
048 */
049 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
050 {
051 if (par1IBlockAccess.getBlockId(par2, par3, par4 - 1) == this.blockID)
052 {
053 this.setBlockBounds(0.0625F, 0.0F, 0.0F, 0.9375F, 0.875F, 0.9375F);
054 }
055 else if (par1IBlockAccess.getBlockId(par2, par3, par4 + 1) == this.blockID)
056 {
057 this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 0.9375F, 0.875F, 1.0F);
058 }
059 else if (par1IBlockAccess.getBlockId(par2 - 1, par3, par4) == this.blockID)
060 {
061 this.setBlockBounds(0.0F, 0.0F, 0.0625F, 0.9375F, 0.875F, 0.9375F);
062 }
063 else if (par1IBlockAccess.getBlockId(par2 + 1, par3, par4) == this.blockID)
064 {
065 this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 1.0F, 0.875F, 0.9375F);
066 }
067 else
068 {
069 this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 0.9375F, 0.875F, 0.9375F);
070 }
071 }
072
073 /**
074 * Called whenever the block is added into the world. Args: world, x, y, z
075 */
076 public void onBlockAdded(World par1World, int par2, int par3, int par4)
077 {
078 super.onBlockAdded(par1World, par2, par3, par4);
079 this.unifyAdjacentChests(par1World, par2, par3, par4);
080 int var5 = par1World.getBlockId(par2, par3, par4 - 1);
081 int var6 = par1World.getBlockId(par2, par3, par4 + 1);
082 int var7 = par1World.getBlockId(par2 - 1, par3, par4);
083 int var8 = par1World.getBlockId(par2 + 1, par3, par4);
084
085 if (var5 == this.blockID)
086 {
087 this.unifyAdjacentChests(par1World, par2, par3, par4 - 1);
088 }
089
090 if (var6 == this.blockID)
091 {
092 this.unifyAdjacentChests(par1World, par2, par3, par4 + 1);
093 }
094
095 if (var7 == this.blockID)
096 {
097 this.unifyAdjacentChests(par1World, par2 - 1, par3, par4);
098 }
099
100 if (var8 == this.blockID)
101 {
102 this.unifyAdjacentChests(par1World, par2 + 1, par3, par4);
103 }
104 }
105
106 /**
107 * Called when the block is placed in the world.
108 */
109 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving)
110 {
111 int var6 = par1World.getBlockId(par2, par3, par4 - 1);
112 int var7 = par1World.getBlockId(par2, par3, par4 + 1);
113 int var8 = par1World.getBlockId(par2 - 1, par3, par4);
114 int var9 = par1World.getBlockId(par2 + 1, par3, par4);
115 byte var10 = 0;
116 int var11 = MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
117
118 if (var11 == 0)
119 {
120 var10 = 2;
121 }
122
123 if (var11 == 1)
124 {
125 var10 = 5;
126 }
127
128 if (var11 == 2)
129 {
130 var10 = 3;
131 }
132
133 if (var11 == 3)
134 {
135 var10 = 4;
136 }
137
138 if (var6 != this.blockID && var7 != this.blockID && var8 != this.blockID && var9 != this.blockID)
139 {
140 par1World.setBlockMetadataWithNotify(par2, par3, par4, var10);
141 }
142 else
143 {
144 if ((var6 == this.blockID || var7 == this.blockID) && (var10 == 4 || var10 == 5))
145 {
146 if (var6 == this.blockID)
147 {
148 par1World.setBlockMetadataWithNotify(par2, par3, par4 - 1, var10);
149 }
150 else
151 {
152 par1World.setBlockMetadataWithNotify(par2, par3, par4 + 1, var10);
153 }
154
155 par1World.setBlockMetadataWithNotify(par2, par3, par4, var10);
156 }
157
158 if ((var8 == this.blockID || var9 == this.blockID) && (var10 == 2 || var10 == 3))
159 {
160 if (var8 == this.blockID)
161 {
162 par1World.setBlockMetadataWithNotify(par2 - 1, par3, par4, var10);
163 }
164 else
165 {
166 par1World.setBlockMetadataWithNotify(par2 + 1, par3, par4, var10);
167 }
168
169 par1World.setBlockMetadataWithNotify(par2, par3, par4, var10);
170 }
171 }
172 }
173
174 /**
175 * Turns the adjacent chests to a double chest.
176 */
177 public void unifyAdjacentChests(World par1World, int par2, int par3, int par4)
178 {
179 if (!par1World.isRemote)
180 {
181 int var5 = par1World.getBlockId(par2, par3, par4 - 1);
182 int var6 = par1World.getBlockId(par2, par3, par4 + 1);
183 int var7 = par1World.getBlockId(par2 - 1, par3, par4);
184 int var8 = par1World.getBlockId(par2 + 1, par3, par4);
185 boolean var9 = true;
186 int var10;
187 int var11;
188 boolean var12;
189 byte var13;
190 int var14;
191
192 if (var5 != this.blockID && var6 != this.blockID)
193 {
194 if (var7 != this.blockID && var8 != this.blockID)
195 {
196 var13 = 3;
197
198 if (Block.opaqueCubeLookup[var5] && !Block.opaqueCubeLookup[var6])
199 {
200 var13 = 3;
201 }
202
203 if (Block.opaqueCubeLookup[var6] && !Block.opaqueCubeLookup[var5])
204 {
205 var13 = 2;
206 }
207
208 if (Block.opaqueCubeLookup[var7] && !Block.opaqueCubeLookup[var8])
209 {
210 var13 = 5;
211 }
212
213 if (Block.opaqueCubeLookup[var8] && !Block.opaqueCubeLookup[var7])
214 {
215 var13 = 4;
216 }
217 }
218 else
219 {
220 var10 = par1World.getBlockId(var7 == this.blockID ? par2 - 1 : par2 + 1, par3, par4 - 1);
221 var11 = par1World.getBlockId(var7 == this.blockID ? par2 - 1 : par2 + 1, par3, par4 + 1);
222 var13 = 3;
223 var12 = true;
224
225 if (var7 == this.blockID)
226 {
227 var14 = par1World.getBlockMetadata(par2 - 1, par3, par4);
228 }
229 else
230 {
231 var14 = par1World.getBlockMetadata(par2 + 1, par3, par4);
232 }
233
234 if (var14 == 2)
235 {
236 var13 = 2;
237 }
238
239 if ((Block.opaqueCubeLookup[var5] || Block.opaqueCubeLookup[var10]) && !Block.opaqueCubeLookup[var6] && !Block.opaqueCubeLookup[var11])
240 {
241 var13 = 3;
242 }
243
244 if ((Block.opaqueCubeLookup[var6] || Block.opaqueCubeLookup[var11]) && !Block.opaqueCubeLookup[var5] && !Block.opaqueCubeLookup[var10])
245 {
246 var13 = 2;
247 }
248 }
249 }
250 else
251 {
252 var10 = par1World.getBlockId(par2 - 1, par3, var5 == this.blockID ? par4 - 1 : par4 + 1);
253 var11 = par1World.getBlockId(par2 + 1, par3, var5 == this.blockID ? par4 - 1 : par4 + 1);
254 var13 = 5;
255 var12 = true;
256
257 if (var5 == this.blockID)
258 {
259 var14 = par1World.getBlockMetadata(par2, par3, par4 - 1);
260 }
261 else
262 {
263 var14 = par1World.getBlockMetadata(par2, par3, par4 + 1);
264 }
265
266 if (var14 == 4)
267 {
268 var13 = 4;
269 }
270
271 if ((Block.opaqueCubeLookup[var7] || Block.opaqueCubeLookup[var10]) && !Block.opaqueCubeLookup[var8] && !Block.opaqueCubeLookup[var11])
272 {
273 var13 = 5;
274 }
275
276 if ((Block.opaqueCubeLookup[var8] || Block.opaqueCubeLookup[var11]) && !Block.opaqueCubeLookup[var7] && !Block.opaqueCubeLookup[var10])
277 {
278 var13 = 4;
279 }
280 }
281
282 par1World.setBlockMetadataWithNotify(par2, par3, par4, var13);
283 }
284 }
285
286 @SideOnly(Side.CLIENT)
287
288 /**
289 * Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side
290 */
291 public int getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
292 {
293 return 4;
294 }
295
296 /**
297 * Returns the block texture based on the side being looked at. Args: side
298 */
299 public int getBlockTextureFromSide(int par1)
300 {
301 return 4;
302 }
303
304 /**
305 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
306 */
307 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
308 {
309 int var5 = 0;
310
311 if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID)
312 {
313 ++var5;
314 }
315
316 if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID)
317 {
318 ++var5;
319 }
320
321 if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID)
322 {
323 ++var5;
324 }
325
326 if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)
327 {
328 ++var5;
329 }
330
331 return var5 > 1 ? false : (this.isThereANeighborChest(par1World, par2 - 1, par3, par4) ? false : (this.isThereANeighborChest(par1World, par2 + 1, par3, par4) ? false : (this.isThereANeighborChest(par1World, par2, par3, par4 - 1) ? false : !this.isThereANeighborChest(par1World, par2, par3, par4 + 1))));
332 }
333
334 /**
335 * Checks the neighbor blocks to see if there is a chest there. Args: world, x, y, z
336 */
337 private boolean isThereANeighborChest(World par1World, int par2, int par3, int par4)
338 {
339 return par1World.getBlockId(par2, par3, par4) != this.blockID ? false : (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID ? true : (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID ? true : (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID ? true : par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)));
340 }
341
342 /**
343 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
344 * their own) Args: x, y, z, neighbor blockID
345 */
346 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
347 {
348 super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
349 TileEntityChest var6 = (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4);
350
351 if (var6 != null)
352 {
353 var6.updateContainingBlockInfo();
354 }
355 }
356
357 /**
358 * ejects contained items into the world, and notifies neighbours of an update, as appropriate
359 */
360 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
361 {
362 TileEntityChest var7 = (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4);
363
364 if (var7 != null)
365 {
366 for (int var8 = 0; var8 < var7.getSizeInventory(); ++var8)
367 {
368 ItemStack var9 = var7.getStackInSlot(var8);
369
370 if (var9 != null)
371 {
372 float var10 = this.random.nextFloat() * 0.8F + 0.1F;
373 float var11 = this.random.nextFloat() * 0.8F + 0.1F;
374 EntityItem var14;
375
376 for (float var12 = this.random.nextFloat() * 0.8F + 0.1F; var9.stackSize > 0; par1World.spawnEntityInWorld(var14))
377 {
378 int var13 = this.random.nextInt(21) + 10;
379
380 if (var13 > var9.stackSize)
381 {
382 var13 = var9.stackSize;
383 }
384
385 var9.stackSize -= var13;
386 var14 = new EntityItem(par1World, (double)((float)par2 + var10), (double)((float)par3 + var11), (double)((float)par4 + var12), new ItemStack(var9.itemID, var13, var9.getItemDamage()));
387 float var15 = 0.05F;
388 var14.motionX = (double)((float)this.random.nextGaussian() * var15);
389 var14.motionY = (double)((float)this.random.nextGaussian() * var15 + 0.2F);
390 var14.motionZ = (double)((float)this.random.nextGaussian() * var15);
391
392 if (var9.hasTagCompound())
393 {
394 var14.item.setTagCompound((NBTTagCompound)var9.getTagCompound().copy());
395 }
396 }
397 }
398 }
399 }
400
401 super.breakBlock(par1World, par2, par3, par4, par5, par6);
402 }
403
404 /**
405 * Called upon block activation (right click on the block.)
406 */
407 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
408 {
409 Object var10 = (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4);
410
411 if (var10 == null)
412 {
413 return true;
414 }
415 else if (par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN))
416 {
417 return true;
418 }
419 else if (isOcelotBlockingChest(par1World, par2, par3, par4))
420 {
421 return true;
422 }
423 else if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 - 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 - 1, par3, par4)))
424 {
425 return true;
426 }
427 else if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 + 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 + 1, par3, par4)))
428 {
429 return true;
430 }
431 else if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 - 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 - 1)))
432 {
433 return true;
434 }
435 else if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 + 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 + 1)))
436 {
437 return true;
438 }
439 else
440 {
441 if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID)
442 {
443 var10 = new InventoryLargeChest("container.chestDouble", (TileEntityChest)par1World.getBlockTileEntity(par2 - 1, par3, par4), (IInventory)var10);
444 }
445
446 if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID)
447 {
448 var10 = new InventoryLargeChest("container.chestDouble", (IInventory)var10, (TileEntityChest)par1World.getBlockTileEntity(par2 + 1, par3, par4));
449 }
450
451 if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID)
452 {
453 var10 = new InventoryLargeChest("container.chestDouble", (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4 - 1), (IInventory)var10);
454 }
455
456 if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)
457 {
458 var10 = new InventoryLargeChest("container.chestDouble", (IInventory)var10, (TileEntityChest)par1World.getBlockTileEntity(par2, par3, par4 + 1));
459 }
460
461 if (par1World.isRemote)
462 {
463 return true;
464 }
465 else
466 {
467 par5EntityPlayer.displayGUIChest((IInventory)var10);
468 return true;
469 }
470 }
471 }
472
473 /**
474 * Returns a new instance of a block's tile entity class. Called on placing the block.
475 */
476 public TileEntity createNewTileEntity(World par1World)
477 {
478 return new TileEntityChest();
479 }
480
481 /**
482 * Looks for a sitting ocelot within certain bounds. Such an ocelot is considered to be blocking access to the
483 * chest.
484 */
485 public static boolean isOcelotBlockingChest(World par0World, int par1, int par2, int par3)
486 {
487 Iterator var4 = par0World.getEntitiesWithinAABB(EntityOcelot.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)par1, (double)(par2 + 1), (double)par3, (double)(par1 + 1), (double)(par2 + 2), (double)(par3 + 1))).iterator();
488 EntityOcelot var6;
489
490 do
491 {
492 if (!var4.hasNext())
493 {
494 return false;
495 }
496
497 EntityOcelot var5 = (EntityOcelot)var4.next();
498 var6 = (EntityOcelot)var5;
499 }
500 while (!var6.isSitting());
501
502 return true;
503 }
504 }