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