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    public void func_94332_a(IconRegister par1IconRegister) {}
651}