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    }