001 package net.minecraft.block; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import java.util.List; 006 import java.util.Random; 007 import net.minecraft.creativetab.CreativeTabs; 008 import net.minecraft.entity.Entity; 009 import net.minecraft.entity.EntityLiving; 010 import net.minecraft.entity.player.EntityPlayer; 011 import net.minecraft.util.AxisAlignedBB; 012 import net.minecraft.util.MathHelper; 013 import net.minecraft.util.MovingObjectPosition; 014 import net.minecraft.util.Vec3; 015 import net.minecraft.world.IBlockAccess; 016 import net.minecraft.world.World; 017 018 public class BlockStairs extends Block 019 { 020 private static final int[][] field_72159_a = new int[][] {{2, 6}, {3, 7}, {2, 3}, {6, 7}, {0, 4}, {1, 5}, {0, 1}, {4, 5}}; 021 private static final int[] field_82545_b = new int[] {1, -1, 0, 0}; 022 private static final int[] field_82546_c = new int[] {0, 0, 1, -1}; 023 024 /** The block that is used as model for the stair. */ 025 private final Block modelBlock; 026 private final int field_72158_c; 027 private boolean field_72156_cr = false; 028 private int field_72160_cs = 0; 029 030 protected BlockStairs(int par1, Block par2Block, int par3) 031 { 032 super(par1, par2Block.blockIndexInTexture, par2Block.blockMaterial); 033 this.modelBlock = par2Block; 034 this.field_72158_c = par3; 035 this.setHardness(par2Block.blockHardness); 036 this.setResistance(par2Block.blockResistance / 3.0F); 037 this.setStepSound(par2Block.stepSound); 038 this.setLightOpacity(255); 039 this.setCreativeTab(CreativeTabs.tabBlock); 040 } 041 042 /** 043 * Updates the blocks bounds based on its current state. Args: world, x, y, z 044 */ 045 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 046 { 047 if (this.field_72156_cr) 048 { 049 this.setBlockBounds(0.5F * (float)(this.field_72160_cs % 2), 0.5F * (float)(this.field_72160_cs / 2 % 2), 0.5F * (float)(this.field_72160_cs / 4 % 2), 0.5F + 0.5F * (float)(this.field_72160_cs % 2), 0.5F + 0.5F * (float)(this.field_72160_cs / 2 % 2), 0.5F + 0.5F * (float)(this.field_72160_cs / 4 % 2)); 050 } 051 else 052 { 053 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 054 } 055 } 056 057 /** 058 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 059 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 060 */ 061 public boolean isOpaqueCube() 062 { 063 return false; 064 } 065 066 /** 067 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 068 */ 069 public boolean renderAsNormalBlock() 070 { 071 return false; 072 } 073 074 /** 075 * The type of render function that is called for this block 076 */ 077 public int getRenderType() 078 { 079 return 10; 080 } 081 082 public void func_82541_d(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 083 { 084 int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 085 086 if ((var5 & 4) != 0) 087 { 088 this.setBlockBounds(0.0F, 0.5F, 0.0F, 1.0F, 1.0F, 1.0F); 089 } 090 else 091 { 092 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F); 093 } 094 } 095 096 /** 097 * Checks if supplied ID is one of a BlockStairs 098 */ 099 public static boolean isBlockStairsID(int par0) 100 { 101 return par0 > 0 && Block.blocksList[par0] instanceof BlockStairs; 102 } 103 104 private boolean func_82540_f(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 105 { 106 int var6 = par1IBlockAccess.getBlockId(par2, par3, par4); 107 return isBlockStairsID(var6) && par1IBlockAccess.getBlockMetadata(par2, par3, par4) == par5; 108 } 109 110 public boolean func_82542_g(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 111 { 112 int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 113 int var6 = var5 & 3; 114 float var7 = 0.5F; 115 float var8 = 1.0F; 116 117 if ((var5 & 4) != 0) 118 { 119 var7 = 0.0F; 120 var8 = 0.5F; 121 } 122 123 float var9 = 0.0F; 124 float var10 = 1.0F; 125 float var11 = 0.0F; 126 float var12 = 0.5F; 127 boolean var13 = true; 128 int var14; 129 int var15; 130 int var16; 131 132 if (var6 == 0) 133 { 134 var9 = 0.5F; 135 var12 = 1.0F; 136 var14 = par1IBlockAccess.getBlockId(par2 + 1, par3, par4); 137 var15 = par1IBlockAccess.getBlockMetadata(par2 + 1, par3, par4); 138 139 if (isBlockStairsID(var14) && (var5 & 4) == (var15 & 4)) 140 { 141 var16 = var15 & 3; 142 143 if (var16 == 3 && !this.func_82540_f(par1IBlockAccess, par2, par3, par4 + 1, var5)) 144 { 145 var12 = 0.5F; 146 var13 = false; 147 } 148 else if (var16 == 2 && !this.func_82540_f(par1IBlockAccess, par2, par3, par4 - 1, var5)) 149 { 150 var11 = 0.5F; 151 var13 = false; 152 } 153 } 154 } 155 else if (var6 == 1) 156 { 157 var10 = 0.5F; 158 var12 = 1.0F; 159 var14 = par1IBlockAccess.getBlockId(par2 - 1, par3, par4); 160 var15 = par1IBlockAccess.getBlockMetadata(par2 - 1, par3, par4); 161 162 if (isBlockStairsID(var14) && (var5 & 4) == (var15 & 4)) 163 { 164 var16 = var15 & 3; 165 166 if (var16 == 3 && !this.func_82540_f(par1IBlockAccess, par2, par3, par4 + 1, var5)) 167 { 168 var12 = 0.5F; 169 var13 = false; 170 } 171 else if (var16 == 2 && !this.func_82540_f(par1IBlockAccess, par2, par3, par4 - 1, var5)) 172 { 173 var11 = 0.5F; 174 var13 = false; 175 } 176 } 177 } 178 else if (var6 == 2) 179 { 180 var11 = 0.5F; 181 var12 = 1.0F; 182 var14 = par1IBlockAccess.getBlockId(par2, par3, par4 + 1); 183 var15 = par1IBlockAccess.getBlockMetadata(par2, par3, par4 + 1); 184 185 if (isBlockStairsID(var14) && (var5 & 4) == (var15 & 4)) 186 { 187 var16 = var15 & 3; 188 189 if (var16 == 1 && !this.func_82540_f(par1IBlockAccess, par2 + 1, par3, par4, var5)) 190 { 191 var10 = 0.5F; 192 var13 = false; 193 } 194 else if (var16 == 0 && !this.func_82540_f(par1IBlockAccess, par2 - 1, par3, par4, var5)) 195 { 196 var9 = 0.5F; 197 var13 = false; 198 } 199 } 200 } 201 else if (var6 == 3) 202 { 203 var14 = par1IBlockAccess.getBlockId(par2, par3, par4 - 1); 204 var15 = par1IBlockAccess.getBlockMetadata(par2, par3, par4 - 1); 205 206 if (isBlockStairsID(var14) && (var5 & 4) == (var15 & 4)) 207 { 208 var16 = var15 & 3; 209 210 if (var16 == 1 && !this.func_82540_f(par1IBlockAccess, par2 + 1, par3, par4, var5)) 211 { 212 var10 = 0.5F; 213 var13 = false; 214 } 215 else if (var16 == 0 && !this.func_82540_f(par1IBlockAccess, par2 - 1, par3, par4, var5)) 216 { 217 var9 = 0.5F; 218 var13 = false; 219 } 220 } 221 } 222 223 this.setBlockBounds(var9, var7, var11, var10, var8, var12); 224 return var13; 225 } 226 227 public boolean func_82544_h(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 228 { 229 int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 230 int var6 = var5 & 3; 231 float var7 = 0.5F; 232 float var8 = 1.0F; 233 234 if ((var5 & 4) != 0) 235 { 236 var7 = 0.0F; 237 var8 = 0.5F; 238 } 239 240 float var9 = 0.0F; 241 float var10 = 0.5F; 242 float var11 = 0.5F; 243 float var12 = 1.0F; 244 boolean var13 = false; 245 int var14; 246 int var15; 247 int var16; 248 249 if (var6 == 0) 250 { 251 var14 = par1IBlockAccess.getBlockId(par2 - 1, par3, par4); 252 var15 = par1IBlockAccess.getBlockMetadata(par2 - 1, par3, par4); 253 254 if (isBlockStairsID(var14) && (var5 & 4) == (var15 & 4)) 255 { 256 var16 = var15 & 3; 257 258 if (var16 == 3 && !this.func_82540_f(par1IBlockAccess, par2, par3, par4 - 1, var5)) 259 { 260 var11 = 0.0F; 261 var12 = 0.5F; 262 var13 = true; 263 } 264 else if (var16 == 2 && !this.func_82540_f(par1IBlockAccess, par2, par3, par4 + 1, var5)) 265 { 266 var11 = 0.5F; 267 var12 = 1.0F; 268 var13 = true; 269 } 270 } 271 } 272 else if (var6 == 1) 273 { 274 var14 = par1IBlockAccess.getBlockId(par2 + 1, par3, par4); 275 var15 = par1IBlockAccess.getBlockMetadata(par2 + 1, par3, par4); 276 277 if (isBlockStairsID(var14) && (var5 & 4) == (var15 & 4)) 278 { 279 var9 = 0.5F; 280 var10 = 1.0F; 281 var16 = var15 & 3; 282 283 if (var16 == 3 && !this.func_82540_f(par1IBlockAccess, par2, par3, par4 - 1, var5)) 284 { 285 var11 = 0.0F; 286 var12 = 0.5F; 287 var13 = true; 288 } 289 else if (var16 == 2 && !this.func_82540_f(par1IBlockAccess, par2, par3, par4 + 1, var5)) 290 { 291 var11 = 0.5F; 292 var12 = 1.0F; 293 var13 = true; 294 } 295 } 296 } 297 else if (var6 == 2) 298 { 299 var14 = par1IBlockAccess.getBlockId(par2, par3, par4 - 1); 300 var15 = par1IBlockAccess.getBlockMetadata(par2, par3, par4 - 1); 301 302 if (isBlockStairsID(var14) && (var5 & 4) == (var15 & 4)) 303 { 304 var11 = 0.0F; 305 var12 = 0.5F; 306 var16 = var15 & 3; 307 308 if (var16 == 1 && !this.func_82540_f(par1IBlockAccess, par2 - 1, par3, par4, var5)) 309 { 310 var13 = true; 311 } 312 else if (var16 == 0 && !this.func_82540_f(par1IBlockAccess, par2 + 1, par3, par4, var5)) 313 { 314 var9 = 0.5F; 315 var10 = 1.0F; 316 var13 = true; 317 } 318 } 319 } 320 else if (var6 == 3) 321 { 322 var14 = par1IBlockAccess.getBlockId(par2, par3, par4 + 1); 323 var15 = par1IBlockAccess.getBlockMetadata(par2, par3, par4 + 1); 324 325 if (isBlockStairsID(var14) && (var5 & 4) == (var15 & 4)) 326 { 327 var16 = var15 & 3; 328 329 if (var16 == 1 && !this.func_82540_f(par1IBlockAccess, par2 - 1, par3, par4, var5)) 330 { 331 var13 = true; 332 } 333 else if (var16 == 0 && !this.func_82540_f(par1IBlockAccess, par2 + 1, par3, par4, var5)) 334 { 335 var9 = 0.5F; 336 var10 = 1.0F; 337 var13 = true; 338 } 339 } 340 } 341 342 if (var13) 343 { 344 this.setBlockBounds(var9, var7, var11, var10, var8, var12); 345 } 346 347 return var13; 348 } 349 350 /** 351 * if the specified block is in the given AABB, add its collision bounding box to the given list 352 */ 353 public void addCollidingBlockToList(World par1World, int par2, int par3, int par4, AxisAlignedBB par5AxisAlignedBB, List par6List, Entity par7Entity) 354 { 355 this.func_82541_d(par1World, par2, par3, par4); 356 super.addCollidingBlockToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity); 357 boolean var8 = this.func_82542_g(par1World, par2, par3, par4); 358 super.addCollidingBlockToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity); 359 360 if (var8 && this.func_82544_h(par1World, par2, par3, par4)) 361 { 362 super.addCollidingBlockToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity); 363 } 364 365 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 366 } 367 368 @SideOnly(Side.CLIENT) 369 370 /** 371 * A randomly called display update to be able to add particles or other items for display 372 */ 373 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random) 374 { 375 this.modelBlock.randomDisplayTick(par1World, par2, par3, par4, par5Random); 376 } 377 378 /** 379 * Called when the block is clicked by a player. Args: x, y, z, entityPlayer 380 */ 381 public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer) 382 { 383 this.modelBlock.onBlockClicked(par1World, par2, par3, par4, par5EntityPlayer); 384 } 385 386 /** 387 * Called right before the block is destroyed by a player. Args: world, x, y, z, metaData 388 */ 389 public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) 390 { 391 this.modelBlock.onBlockDestroyedByPlayer(par1World, par2, par3, par4, par5); 392 } 393 394 @SideOnly(Side.CLIENT) 395 396 /** 397 * Goes straight to getLightBrightnessForSkyBlocks for Blocks, does some fancy computing for Fluids 398 */ 399 public int getMixedBrightnessForBlock(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 400 { 401 return this.modelBlock.getMixedBrightnessForBlock(par1IBlockAccess, par2, par3, par4); 402 } 403 404 @SideOnly(Side.CLIENT) 405 406 /** 407 * How bright to render this block based on the light its receiving. Args: iBlockAccess, x, y, z 408 */ 409 public float getBlockBrightness(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 410 { 411 return this.modelBlock.getBlockBrightness(par1IBlockAccess, par2, par3, par4); 412 } 413 414 /** 415 * Returns how much this block can resist explosions from the passed in entity. 416 */ 417 public float getExplosionResistance(Entity par1Entity) 418 { 419 return this.modelBlock.getExplosionResistance(par1Entity); 420 } 421 422 /** 423 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 424 */ 425 public int getBlockTextureFromSideAndMetadata(int par1, int par2) 426 { 427 return this.modelBlock.getBlockTextureFromSideAndMetadata(par1, this.field_72158_c); 428 } 429 430 /** 431 * Returns the block texture based on the side being looked at. Args: side 432 */ 433 public int getBlockTextureFromSide(int par1) 434 { 435 return this.modelBlock.getBlockTextureFromSideAndMetadata(par1, this.field_72158_c); 436 } 437 438 @SideOnly(Side.CLIENT) 439 440 /** 441 * Returns which pass should this block be rendered on. 0 for solids and 1 for alpha 442 */ 443 public int getRenderBlockPass() 444 { 445 return this.modelBlock.getRenderBlockPass(); 446 } 447 448 /** 449 * How many world ticks before ticking 450 */ 451 public int tickRate() 452 { 453 return this.modelBlock.tickRate(); 454 } 455 456 @SideOnly(Side.CLIENT) 457 458 /** 459 * Returns the bounding box of the wired rectangular prism to render. 460 */ 461 public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 462 { 463 return this.modelBlock.getSelectedBoundingBoxFromPool(par1World, par2, par3, par4); 464 } 465 466 /** 467 * Can add to the passed in vector for a movement vector to be applied to the entity. Args: x, y, z, entity, vec3d 468 */ 469 public void velocityToAddToEntity(World par1World, int par2, int par3, int par4, Entity par5Entity, Vec3 par6Vec3) 470 { 471 this.modelBlock.velocityToAddToEntity(par1World, par2, par3, par4, par5Entity, par6Vec3); 472 } 473 474 /** 475 * Returns if this block is collidable (only used by Fire). Args: x, y, z 476 */ 477 public boolean isCollidable() 478 { 479 return this.modelBlock.isCollidable(); 480 } 481 482 /** 483 * Returns whether this block is collideable based on the arguments passed in Args: blockMetaData, unknownFlag 484 */ 485 public boolean canCollideCheck(int par1, boolean par2) 486 { 487 return this.modelBlock.canCollideCheck(par1, par2); 488 } 489 490 /** 491 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 492 */ 493 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 494 { 495 return this.modelBlock.canPlaceBlockAt(par1World, par2, par3, par4); 496 } 497 498 /** 499 * Called whenever the block is added into the world. Args: world, x, y, z 500 */ 501 public void onBlockAdded(World par1World, int par2, int par3, int par4) 502 { 503 this.onNeighborBlockChange(par1World, par2, par3, par4, 0); 504 this.modelBlock.onBlockAdded(par1World, par2, par3, par4); 505 } 506 507 /** 508 * ejects contained items into the world, and notifies neighbours of an update, as appropriate 509 */ 510 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) 511 { 512 this.modelBlock.breakBlock(par1World, par2, par3, par4, par5, par6); 513 } 514 515 /** 516 * Called whenever an entity is walking on top of this block. Args: world, x, y, z, entity 517 */ 518 public void onEntityWalking(World par1World, int par2, int par3, int par4, Entity par5Entity) 519 { 520 this.modelBlock.onEntityWalking(par1World, par2, par3, par4, par5Entity); 521 } 522 523 /** 524 * Ticks the block if it's been scheduled 525 */ 526 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) 527 { 528 this.modelBlock.updateTick(par1World, par2, par3, par4, par5Random); 529 } 530 531 /** 532 * Called upon block activation (right click on the block.) 533 */ 534 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 535 { 536 return this.modelBlock.onBlockActivated(par1World, par2, par3, par4, par5EntityPlayer, 0, 0.0F, 0.0F, 0.0F); 537 } 538 539 /** 540 * Called upon the block being destroyed by an explosion 541 */ 542 public void onBlockDestroyedByExplosion(World par1World, int par2, int par3, int par4) 543 { 544 this.modelBlock.onBlockDestroyedByExplosion(par1World, par2, par3, par4); 545 } 546 547 /** 548 * Called when the block is placed in the world. 549 */ 550 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving) 551 { 552 int var6 = MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3; 553 int var7 = par1World.getBlockMetadata(par2, par3, par4) & 4; 554 555 if (var6 == 0) 556 { 557 par1World.setBlockMetadataWithNotify(par2, par3, par4, 2 | var7); 558 } 559 560 if (var6 == 1) 561 { 562 par1World.setBlockMetadataWithNotify(par2, par3, par4, 1 | var7); 563 } 564 565 if (var6 == 2) 566 { 567 par1World.setBlockMetadataWithNotify(par2, par3, par4, 3 | var7); 568 } 569 570 if (var6 == 3) 571 { 572 par1World.setBlockMetadataWithNotify(par2, par3, par4, 0 | var7); 573 } 574 } 575 576 /** 577 * Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata 578 */ 579 public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9) 580 { 581 return par5 != 0 && (par5 == 1 || (double)par7 <= 0.5D) ? par9 : par9 | 4; 582 } 583 584 /** 585 * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world, 586 * x, y, z, startVec, endVec 587 */ 588 public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3) 589 { 590 MovingObjectPosition[] var7 = new MovingObjectPosition[8]; 591 int var8 = par1World.getBlockMetadata(par2, par3, par4); 592 int var9 = var8 & 3; 593 boolean var10 = (var8 & 4) == 4; 594 int[] var11 = field_72159_a[var9 + (var10 ? 4 : 0)]; 595 this.field_72156_cr = true; 596 int var14; 597 int var15; 598 int var16; 599 600 for (int var12 = 0; var12 < 8; ++var12) 601 { 602 this.field_72160_cs = var12; 603 int[] var13 = var11; 604 var14 = var11.length; 605 606 for (var15 = 0; var15 < var14; ++var15) 607 { 608 var16 = var13[var15]; 609 610 if (var16 == var12) 611 { 612 ; 613 } 614 } 615 616 var7[var12] = super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3); 617 } 618 619 int[] var21 = var11; 620 int var24 = var11.length; 621 622 for (var14 = 0; var14 < var24; ++var14) 623 { 624 var15 = var21[var14]; 625 var7[var15] = null; 626 } 627 628 MovingObjectPosition var23 = null; 629 double var22 = 0.0D; 630 MovingObjectPosition[] var25 = var7; 631 var16 = var7.length; 632 633 for (int var17 = 0; var17 < var16; ++var17) 634 { 635 MovingObjectPosition var18 = var25[var17]; 636 637 if (var18 != null) 638 { 639 double var19 = var18.hitVec.squareDistanceTo(par6Vec3); 640 641 if (var19 > var22) 642 { 643 var23 = var18; 644 var22 = var19; 645 } 646 } 647 } 648 649 return var23; 650 } 651 }