001package net.minecraft.block; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.Random; 006import net.minecraft.block.material.Material; 007import net.minecraft.client.renderer.IconFlipped; 008import net.minecraft.client.renderer.texture.IconRegister; 009import net.minecraft.entity.player.EntityPlayer; 010import net.minecraft.item.Item; 011import net.minecraft.util.AxisAlignedBB; 012import net.minecraft.util.Icon; 013import net.minecraft.util.MovingObjectPosition; 014import net.minecraft.util.Vec3; 015import net.minecraft.world.IBlockAccess; 016import net.minecraft.world.World; 017 018public class BlockDoor extends Block 019{ 020 private static final String[] field_94467_a = new String[] {"doorWood_lower", "doorWood_upper", "doorIron_lower", "doorIron_upper"}; 021 private final int field_94465_b; 022 @SideOnly(Side.CLIENT) 023 private Icon[] iconArray; 024 025 protected BlockDoor(int par1, Material par2Material) 026 { 027 super(par1, par2Material); 028 029 if (par2Material == Material.iron) 030 { 031 this.field_94465_b = 2; 032 } 033 else 034 { 035 this.field_94465_b = 0; 036 } 037 038 float f = 0.5F; 039 float f1 = 1.0F; 040 this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f); 041 } 042 043 @SideOnly(Side.CLIENT) 044 045 /** 046 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 047 */ 048 public Icon getBlockTextureFromSideAndMetadata(int par1, int par2) 049 { 050 return this.iconArray[this.field_94465_b]; 051 } 052 053 @SideOnly(Side.CLIENT) 054 055 /** 056 * Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side 057 */ 058 public Icon getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 059 { 060 if (par5 != 1 && par5 != 0) 061 { 062 int i1 = this.getFullMetadata(par1IBlockAccess, par2, par3, par4); 063 int j1 = i1 & 3; 064 boolean flag = (i1 & 4) != 0; 065 boolean flag1 = false; 066 boolean flag2 = (i1 & 8) != 0; 067 068 if (flag) 069 { 070 if (j1 == 0 && par5 == 2) 071 { 072 flag1 = !flag1; 073 } 074 else if (j1 == 1 && par5 == 5) 075 { 076 flag1 = !flag1; 077 } 078 else if (j1 == 2 && par5 == 3) 079 { 080 flag1 = !flag1; 081 } 082 else if (j1 == 3 && par5 == 4) 083 { 084 flag1 = !flag1; 085 } 086 } 087 else 088 { 089 if (j1 == 0 && par5 == 5) 090 { 091 flag1 = !flag1; 092 } 093 else if (j1 == 1 && par5 == 3) 094 { 095 flag1 = !flag1; 096 } 097 else if (j1 == 2 && par5 == 4) 098 { 099 flag1 = !flag1; 100 } 101 else if (j1 == 3 && par5 == 2) 102 { 103 flag1 = !flag1; 104 } 105 106 if ((i1 & 16) != 0) 107 { 108 flag1 = !flag1; 109 } 110 } 111 112 return this.iconArray[this.field_94465_b + (flag1 ? field_94467_a.length : 0) + (flag2 ? 1 : 0)]; 113 } 114 else 115 { 116 return this.iconArray[this.field_94465_b]; 117 } 118 } 119 120 @SideOnly(Side.CLIENT) 121 122 /** 123 * When this method is called, your block should register all the icons it needs with the given IconRegister. This 124 * is the only chance you get to register icons. 125 */ 126 public void registerIcons(IconRegister par1IconRegister) 127 { 128 this.iconArray = new Icon[field_94467_a.length * 2]; 129 130 for (int i = 0; i < field_94467_a.length; ++i) 131 { 132 this.iconArray[i] = par1IconRegister.registerIcon(field_94467_a[i]); 133 this.iconArray[i + field_94467_a.length] = new IconFlipped(this.iconArray[i], true, false); 134 } 135 } 136 137 /** 138 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 139 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 140 */ 141 public boolean isOpaqueCube() 142 { 143 return false; 144 } 145 146 public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 147 { 148 int l = this.getFullMetadata(par1IBlockAccess, par2, par3, par4); 149 return (l & 4) != 0; 150 } 151 152 /** 153 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 154 */ 155 public boolean renderAsNormalBlock() 156 { 157 return false; 158 } 159 160 /** 161 * The type of render function that is called for this block 162 */ 163 public int getRenderType() 164 { 165 return 7; 166 } 167 168 @SideOnly(Side.CLIENT) 169 170 /** 171 * Returns the bounding box of the wired rectangular prism to render. 172 */ 173 public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 174 { 175 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 176 return super.getSelectedBoundingBoxFromPool(par1World, par2, par3, par4); 177 } 178 179 /** 180 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been 181 * cleared to be reused) 182 */ 183 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 184 { 185 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 186 return super.getCollisionBoundingBoxFromPool(par1World, par2, par3, par4); 187 } 188 189 /** 190 * Updates the blocks bounds based on its current state. Args: world, x, y, z 191 */ 192 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 193 { 194 this.setDoorRotation(this.getFullMetadata(par1IBlockAccess, par2, par3, par4)); 195 } 196 197 /** 198 * Returns 0, 1, 2 or 3 depending on where the hinge is. 199 */ 200 public int getDoorOrientation(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 201 { 202 return this.getFullMetadata(par1IBlockAccess, par2, par3, par4) & 3; 203 } 204 205 public boolean isDoorOpen(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 206 { 207 return (this.getFullMetadata(par1IBlockAccess, par2, par3, par4) & 4) != 0; 208 } 209 210 private void setDoorRotation(int par1) 211 { 212 float f = 0.1875F; 213 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 2.0F, 1.0F); 214 int j = par1 & 3; 215 boolean flag = (par1 & 4) != 0; 216 boolean flag1 = (par1 & 16) != 0; 217 218 if (j == 0) 219 { 220 if (flag) 221 { 222 if (!flag1) 223 { 224 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); 225 } 226 else 227 { 228 this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); 229 } 230 } 231 else 232 { 233 this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); 234 } 235 } 236 else if (j == 1) 237 { 238 if (flag) 239 { 240 if (!flag1) 241 { 242 this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 243 } 244 else 245 { 246 this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); 247 } 248 } 249 else 250 { 251 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); 252 } 253 } 254 else if (j == 2) 255 { 256 if (flag) 257 { 258 if (!flag1) 259 { 260 this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); 261 } 262 else 263 { 264 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); 265 } 266 } 267 else 268 { 269 this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 270 } 271 } 272 else if (j == 3) 273 { 274 if (flag) 275 { 276 if (!flag1) 277 { 278 this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); 279 } 280 else 281 { 282 this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 283 } 284 } 285 else 286 { 287 this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); 288 } 289 } 290 } 291 292 /** 293 * Called when the block is clicked by a player. Args: x, y, z, entityPlayer 294 */ 295 public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer) {} 296 297 /** 298 * Called upon block activation (right click on the block.) 299 */ 300 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 301 { 302 if (this.blockMaterial == Material.iron) 303 { 304 return false; //Allow items to interact with the door 305 } 306 else 307 { 308 int i1 = this.getFullMetadata(par1World, par2, par3, par4); 309 int j1 = i1 & 7; 310 j1 ^= 4; 311 312 if ((i1 & 8) == 0) 313 { 314 par1World.setBlockMetadataWithNotify(par2, par3, par4, j1, 2); 315 par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4); 316 } 317 else 318 { 319 par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, j1, 2); 320 par1World.markBlockRangeForRenderUpdate(par2, par3 - 1, par4, par2, par3, par4); 321 } 322 323 par1World.playAuxSFXAtEntity(par5EntityPlayer, 1003, par2, par3, par4, 0); 324 return true; 325 } 326 } 327 328 /** 329 * A function to open a door. 330 */ 331 public void onPoweredBlockChange(World par1World, int par2, int par3, int par4, boolean par5) 332 { 333 int l = this.getFullMetadata(par1World, par2, par3, par4); 334 boolean flag1 = (l & 4) != 0; 335 336 if (flag1 != par5) 337 { 338 int i1 = l & 7; 339 i1 ^= 4; 340 341 if ((l & 8) == 0) 342 { 343 par1World.setBlockMetadataWithNotify(par2, par3, par4, i1, 2); 344 par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4); 345 } 346 else 347 { 348 par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, i1, 2); 349 par1World.markBlockRangeForRenderUpdate(par2, par3 - 1, par4, par2, par3, par4); 350 } 351 352 par1World.playAuxSFXAtEntity((EntityPlayer)null, 1003, par2, par3, par4, 0); 353 } 354 } 355 356 /** 357 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 358 * their own) Args: x, y, z, neighbor blockID 359 */ 360 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 361 { 362 int i1 = par1World.getBlockMetadata(par2, par3, par4); 363 364 if ((i1 & 8) == 0) 365 { 366 boolean flag = false; 367 368 if (par1World.getBlockId(par2, par3 + 1, par4) != this.blockID) 369 { 370 par1World.setBlockToAir(par2, par3, par4); 371 flag = true; 372 } 373 374 if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4)) 375 { 376 par1World.setBlockToAir(par2, par3, par4); 377 flag = true; 378 379 if (par1World.getBlockId(par2, par3 + 1, par4) == this.blockID) 380 { 381 par1World.setBlockToAir(par2, par3 + 1, par4); 382 } 383 } 384 385 if (flag) 386 { 387 if (!par1World.isRemote) 388 { 389 this.dropBlockAsItem(par1World, par2, par3, par4, i1, 0); 390 } 391 } 392 else 393 { 394 boolean flag1 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4); 395 396 if ((flag1 || par5 > 0 && Block.blocksList[par5].canProvidePower()) && par5 != this.blockID) 397 { 398 this.onPoweredBlockChange(par1World, par2, par3, par4, flag1); 399 } 400 } 401 } 402 else 403 { 404 if (par1World.getBlockId(par2, par3 - 1, par4) != this.blockID) 405 { 406 par1World.setBlockToAir(par2, par3, par4); 407 } 408 409 if (par5 > 0 && par5 != this.blockID) 410 { 411 this.onNeighborBlockChange(par1World, par2, par3 - 1, par4, par5); 412 } 413 } 414 } 415 416 /** 417 * Returns the ID of the items to drop on destruction. 418 */ 419 public int idDropped(int par1, Random par2Random, int par3) 420 { 421 return (par1 & 8) != 0 ? 0 : (this.blockMaterial == Material.iron ? Item.doorSteel.itemID : Item.doorWood.itemID); 422 } 423 424 /** 425 * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world, 426 * x, y, z, startVec, endVec 427 */ 428 public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3) 429 { 430 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 431 return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3); 432 } 433 434 /** 435 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 436 */ 437 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 438 { 439 return par3 >= 255 ? false : par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && super.canPlaceBlockAt(par1World, par2, par3, par4) && super.canPlaceBlockAt(par1World, par2, par3 + 1, par4); 440 } 441 442 /** 443 * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility 444 * and stop pistons 445 */ 446 public int getMobilityFlag() 447 { 448 return 1; 449 } 450 451 /** 452 * Returns the full metadata value created by combining the metadata of both blocks the door takes up. 453 */ 454 public int getFullMetadata(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 455 { 456 int l = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 457 boolean flag = (l & 8) != 0; 458 int i1; 459 int j1; 460 461 if (flag) 462 { 463 i1 = par1IBlockAccess.getBlockMetadata(par2, par3 - 1, par4); 464 j1 = l; 465 } 466 else 467 { 468 i1 = l; 469 j1 = par1IBlockAccess.getBlockMetadata(par2, par3 + 1, par4); 470 } 471 472 boolean flag1 = (j1 & 1) != 0; 473 return i1 & 7 | (flag ? 8 : 0) | (flag1 ? 16 : 0); 474 } 475 476 @SideOnly(Side.CLIENT) 477 478 /** 479 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) 480 */ 481 public int idPicked(World par1World, int par2, int par3, int par4) 482 { 483 return this.blockMaterial == Material.iron ? Item.doorSteel.itemID : Item.doorWood.itemID; 484 } 485 486 /** 487 * Called when the block is attempted to be harvested 488 */ 489 public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) 490 { 491 if (par6EntityPlayer.capabilities.isCreativeMode && (par5 & 8) != 0 && par1World.getBlockId(par2, par3 - 1, par4) == this.blockID) 492 { 493 par1World.setBlockToAir(par2, par3 - 1, par4); 494 } 495 } 496}