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