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 }