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