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[] field_94466_c; 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.field_94466_c[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.field_94466_c[this.field_94465_b + (flag1 ? field_94467_a.length : 0) + (flag2 ? 1 : 0)]; 113 } 114 else 115 { 116 return this.field_94466_c[this.field_94465_b]; 117 } 118 } 119 120 @SideOnly(Side.CLIENT) 121 public void func_94332_a(IconRegister par1IconRegister) 122 { 123 this.field_94466_c = new Icon[field_94467_a.length * 2]; 124 125 for (int i = 0; i < field_94467_a.length; ++i) 126 { 127 this.field_94466_c[i] = par1IconRegister.func_94245_a(field_94467_a[i]); 128 this.field_94466_c[i + field_94467_a.length] = new IconFlipped(this.field_94466_c[i], true, false); 129 } 130 } 131 132 /** 133 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 134 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 135 */ 136 public boolean isOpaqueCube() 137 { 138 return false; 139 } 140 141 public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 142 { 143 int l = this.getFullMetadata(par1IBlockAccess, par2, par3, par4); 144 return (l & 4) != 0; 145 } 146 147 /** 148 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 149 */ 150 public boolean renderAsNormalBlock() 151 { 152 return false; 153 } 154 155 /** 156 * The type of render function that is called for this block 157 */ 158 public int getRenderType() 159 { 160 return 7; 161 } 162 163 @SideOnly(Side.CLIENT) 164 165 /** 166 * Returns the bounding box of the wired rectangular prism to render. 167 */ 168 public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 169 { 170 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 171 return super.getSelectedBoundingBoxFromPool(par1World, par2, par3, par4); 172 } 173 174 /** 175 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been 176 * cleared to be reused) 177 */ 178 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 179 { 180 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 181 return super.getCollisionBoundingBoxFromPool(par1World, par2, par3, par4); 182 } 183 184 /** 185 * Updates the blocks bounds based on its current state. Args: world, x, y, z 186 */ 187 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 188 { 189 this.setDoorRotation(this.getFullMetadata(par1IBlockAccess, par2, par3, par4)); 190 } 191 192 /** 193 * Returns 0, 1, 2 or 3 depending on where the hinge is. 194 */ 195 public int getDoorOrientation(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 196 { 197 return this.getFullMetadata(par1IBlockAccess, par2, par3, par4) & 3; 198 } 199 200 public boolean isDoorOpen(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 201 { 202 return (this.getFullMetadata(par1IBlockAccess, par2, par3, par4) & 4) != 0; 203 } 204 205 private void setDoorRotation(int par1) 206 { 207 float f = 0.1875F; 208 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 2.0F, 1.0F); 209 int j = par1 & 3; 210 boolean flag = (par1 & 4) != 0; 211 boolean flag1 = (par1 & 16) != 0; 212 213 if (j == 0) 214 { 215 if (flag) 216 { 217 if (!flag1) 218 { 219 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); 220 } 221 else 222 { 223 this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); 224 } 225 } 226 else 227 { 228 this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); 229 } 230 } 231 else if (j == 1) 232 { 233 if (flag) 234 { 235 if (!flag1) 236 { 237 this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 238 } 239 else 240 { 241 this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); 242 } 243 } 244 else 245 { 246 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); 247 } 248 } 249 else if (j == 2) 250 { 251 if (flag) 252 { 253 if (!flag1) 254 { 255 this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); 256 } 257 else 258 { 259 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f); 260 } 261 } 262 else 263 { 264 this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 265 } 266 } 267 else if (j == 3) 268 { 269 if (flag) 270 { 271 if (!flag1) 272 { 273 this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F); 274 } 275 else 276 { 277 this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 278 } 279 } 280 else 281 { 282 this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F); 283 } 284 } 285 } 286 287 /** 288 * Called when the block is clicked by a player. Args: x, y, z, entityPlayer 289 */ 290 public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer) {} 291 292 /** 293 * Called upon block activation (right click on the block.) 294 */ 295 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 296 { 297 if (this.blockMaterial == Material.iron) 298 { 299 return false; //Allow items to interact with the door 300 } 301 else 302 { 303 int i1 = this.getFullMetadata(par1World, par2, par3, par4); 304 int j1 = i1 & 7; 305 j1 ^= 4; 306 307 if ((i1 & 8) == 0) 308 { 309 par1World.setBlockMetadataWithNotify(par2, par3, par4, j1, 2); 310 par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4); 311 } 312 else 313 { 314 par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, j1, 2); 315 par1World.markBlockRangeForRenderUpdate(par2, par3 - 1, par4, par2, par3, par4); 316 } 317 318 par1World.playAuxSFXAtEntity(par5EntityPlayer, 1003, par2, par3, par4, 0); 319 return true; 320 } 321 } 322 323 /** 324 * A function to open a door. 325 */ 326 public void onPoweredBlockChange(World par1World, int par2, int par3, int par4, boolean par5) 327 { 328 int l = this.getFullMetadata(par1World, par2, par3, par4); 329 boolean flag1 = (l & 4) != 0; 330 331 if (flag1 != par5) 332 { 333 int i1 = l & 7; 334 i1 ^= 4; 335 336 if ((l & 8) == 0) 337 { 338 par1World.setBlockMetadataWithNotify(par2, par3, par4, i1, 2); 339 par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4); 340 } 341 else 342 { 343 par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, i1, 2); 344 par1World.markBlockRangeForRenderUpdate(par2, par3 - 1, par4, par2, par3, par4); 345 } 346 347 par1World.playAuxSFXAtEntity((EntityPlayer)null, 1003, par2, par3, par4, 0); 348 } 349 } 350 351 /** 352 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 353 * their own) Args: x, y, z, neighbor blockID 354 */ 355 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 356 { 357 int i1 = par1World.getBlockMetadata(par2, par3, par4); 358 359 if ((i1 & 8) == 0) 360 { 361 boolean flag = false; 362 363 if (par1World.getBlockId(par2, par3 + 1, par4) != this.blockID) 364 { 365 par1World.func_94571_i(par2, par3, par4); 366 flag = true; 367 } 368 369 if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4)) 370 { 371 par1World.func_94571_i(par2, par3, par4); 372 flag = true; 373 374 if (par1World.getBlockId(par2, par3 + 1, par4) == this.blockID) 375 { 376 par1World.func_94571_i(par2, par3 + 1, par4); 377 } 378 } 379 380 if (flag) 381 { 382 if (!par1World.isRemote) 383 { 384 this.dropBlockAsItem(par1World, par2, par3, par4, i1, 0); 385 } 386 } 387 else 388 { 389 boolean flag1 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4); 390 391 if ((flag1 || par5 > 0 && Block.blocksList[par5].canProvidePower()) && par5 != this.blockID) 392 { 393 this.onPoweredBlockChange(par1World, par2, par3, par4, flag1); 394 } 395 } 396 } 397 else 398 { 399 if (par1World.getBlockId(par2, par3 - 1, par4) != this.blockID) 400 { 401 par1World.func_94571_i(par2, par3, par4); 402 } 403 404 if (par5 > 0 && par5 != this.blockID) 405 { 406 this.onNeighborBlockChange(par1World, par2, par3 - 1, par4, par5); 407 } 408 } 409 } 410 411 /** 412 * Returns the ID of the items to drop on destruction. 413 */ 414 public int idDropped(int par1, Random par2Random, int par3) 415 { 416 return (par1 & 8) != 0 ? 0 : (this.blockMaterial == Material.iron ? Item.doorSteel.itemID : Item.doorWood.itemID); 417 } 418 419 /** 420 * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world, 421 * x, y, z, startVec, endVec 422 */ 423 public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3) 424 { 425 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); 426 return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3); 427 } 428 429 /** 430 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 431 */ 432 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 433 { 434 return par3 >= 255 ? false : par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && super.canPlaceBlockAt(par1World, par2, par3, par4) && super.canPlaceBlockAt(par1World, par2, par3 + 1, par4); 435 } 436 437 /** 438 * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility 439 * and stop pistons 440 */ 441 public int getMobilityFlag() 442 { 443 return 1; 444 } 445 446 /** 447 * Returns the full metadata value created by combining the metadata of both blocks the door takes up. 448 */ 449 public int getFullMetadata(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 450 { 451 int l = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 452 boolean flag = (l & 8) != 0; 453 int i1; 454 int j1; 455 456 if (flag) 457 { 458 i1 = par1IBlockAccess.getBlockMetadata(par2, par3 - 1, par4); 459 j1 = l; 460 } 461 else 462 { 463 i1 = l; 464 j1 = par1IBlockAccess.getBlockMetadata(par2, par3 + 1, par4); 465 } 466 467 boolean flag1 = (j1 & 1) != 0; 468 return i1 & 7 | (flag ? 8 : 0) | (flag1 ? 16 : 0); 469 } 470 471 @SideOnly(Side.CLIENT) 472 473 /** 474 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) 475 */ 476 public int idPicked(World par1World, int par2, int par3, int par4) 477 { 478 return this.blockMaterial == Material.iron ? Item.doorSteel.itemID : Item.doorWood.itemID; 479 } 480 481 /** 482 * Called when the block is attempted to be harvested 483 */ 484 public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) 485 { 486 if (par6EntityPlayer.capabilities.isCreativeMode && (par5 & 8) != 0 && par1World.getBlockId(par2, par3 - 1, par4) == this.blockID) 487 { 488 par1World.func_94571_i(par2, par3 - 1, par4); 489 } 490 } 491}