    001    package net.minecraft.block;
    002
    003    import cpw.mods.fml.relauncher.Side;
    004    import cpw.mods.fml.relauncher.SideOnly;
    005    import java.util.Random;
    006    import net.minecraft.block.material.Material;
    007    import net.minecraft.entity.Entity;
    008    import net.minecraft.util.AxisAlignedBB;
    009    import net.minecraft.util.Vec3;
    010    import net.minecraft.world.IBlockAccess;
    011    import net.minecraft.world.World;
    012
    013    public abstract class BlockFluid extends Block
    014    {
    015        protected BlockFluid(int par1, Material par2Material)
    016        {
    017            super(par1, (par2Material == Material.lava ? 14 : 12) * 16 + 13, par2Material);
    018            float var3 = 0.0F;
    019            float var4 = 0.0F;
    020            this.setBlockBounds(0.0F + var4, 0.0F + var3, 0.0F + var4, 1.0F + var4, 1.0F + var3, 1.0F + var4);
    021            this.setTickRandomly(true);
    022        }
    023
    024        public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    025        {
    026            return this.blockMaterial != Material.lava;
    027        }
    028
    029        @SideOnly(Side.CLIENT)
    030        public int getBlockColor()
    031        {
    032            return 16777215;
    033        }
    034
    035        @SideOnly(Side.CLIENT)
    036
    037        /**
    038         * Returns a integer with hex for 0xrrggbb with this color multiplied against the blocks color. Note only called
    039         * when first determining what to render.
    040         */
    041        public int colorMultiplier(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    042        {
    043            if (this.blockMaterial != Material.water)
    044            {
    045                return 16777215;
    046            }
    047            else
    048            {
    049                int var5 = 0;
    050                int var6 = 0;
    051                int var7 = 0;
    052
    053                for (int var8 = -1; var8 <= 1; ++var8)
    054                {
    055                    for (int var9 = -1; var9 <= 1; ++var9)
    056                    {
    057                        int var10 = par1IBlockAccess.getBiomeGenForCoords(par2 + var9, par4 + var8).getWaterColorMultiplier();
    058                        var5 += (var10 & 16711680) >> 16;
    059                        var6 += (var10 & 65280) >> 8;
    060                        var7 += var10 & 255;
    061                    }
    062                }
    063
    064                return (var5 / 9 & 255) << 16 | (var6 / 9 & 255) << 8 | var7 / 9 & 255;
    065            }
    066        }
    067
    068        /**
    069         * Returns the percentage of the fluid block that is air, based on the given flow decay of the fluid.
    070         */
    071        public static float getFluidHeightPercent(int par0)
    072        {
    073            if (par0 >= 8)
    074            {
    075                par0 = 0;
    076            }
    077
    078            return (float)(par0 + 1) / 9.0F;
    079        }
    080
    081        /**
    082         * Returns the block texture based on the side being looked at.  Args: side
    083         */
    084        public int getBlockTextureFromSide(int par1)
    085        {
    086            return par1 != 0 && par1 != 1 ? this.blockIndexInTexture + 1 : this.blockIndexInTexture;
    087        }
    088
    089        /**
    090         * Returns the amount of fluid decay at the coordinates, or -1 if the block at the coordinates is not the same
    091         * material as the fluid.
    092         */
    093        protected int getFlowDecay(World par1World, int par2, int par3, int par4)
    094        {
    095            return par1World.getBlockMaterial(par2, par3, par4) == this.blockMaterial ? par1World.getBlockMetadata(par2, par3, par4) : -1;
    096        }
    097
    098        /**
    099         * Returns the flow decay but converts values indicating falling liquid (values >=8) to their effective source block
    100         * value of zero.
    101         */
    102        protected int getEffectiveFlowDecay(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    103        {
    104            if (par1IBlockAccess.getBlockMaterial(par2, par3, par4) != this.blockMaterial)
    105            {
    106                return -1;
    107            }
    108            else
    109            {
    110                int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
    111
    112                if (var5 >= 8)
    113                {
    114                    var5 = 0;
    115                }
    116
    117                return var5;
    118            }
    119        }
    120
    121        /**
    122         * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
    123         */
    124        public boolean renderAsNormalBlock()
    125        {
    126            return false;
    127        }
    128
    129        /**
    130         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    131         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    132         */
    133        public boolean isOpaqueCube()
    134        {
    135            return false;
    136        }
    137
    138        /**
    139         * Returns whether this block is collideable based on the arguments passed in Args: blockMetaData, unknownFlag
    140         */
    141        public boolean canCollideCheck(int par1, boolean par2)
    142        {
    143            return par2 && par1 == 0;
    144        }
    145
    146        /**
    147         * Returns Returns true if the given side of this block type should be rendered (if it's solid or not), if the
    148         * adjacent block is at the given coordinates. Args: blockAccess, x, y, z, side
    149         */
    150        public boolean isBlockSolid(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    151        {
    152            Material var6 = par1IBlockAccess.getBlockMaterial(par2, par3, par4);
    153            return var6 == this.blockMaterial ? false : (par5 == 1 ? true : (var6 == Material.ice ? false : super.isBlockSolid(par1IBlockAccess, par2, par3, par4, par5)));
    154        }
    155
    156        @SideOnly(Side.CLIENT)
    157
    158        /**
    159         * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
    160         * coordinates.  Args: blockAccess, x, y, z, side
    161         */
    162        public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    163        {
    164            Material var6 = par1IBlockAccess.getBlockMaterial(par2, par3, par4);
    165            return var6 == this.blockMaterial ? false : (par5 == 1 ? true : (var6 == Material.ice ? false : super.shouldSideBeRendered(par1IBlockAccess, par2, par3, par4, par5)));
    166        }
    167
    168        /**
    169         * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
    170         * cleared to be reused)
    171         */
    172        public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
    173        {
    174            return null;
    175        }
    176
    177        /**
    178         * The type of render function that is called for this block
    179         */
    180        public int getRenderType()
    181        {
    182            return 4;
    183        }
    184
    185        /**
    186         * Returns the ID of the items to drop on destruction.
    187         */
    188        public int idDropped(int par1, Random par2Random, int par3)
    189        {
    190            return 0;
    191        }
    192
    193        /**
    194         * Returns the quantity of items to drop on block destruction.
    195         */
    196        public int quantityDropped(Random par1Random)
    197        {
    198            return 0;
    199        }
    200
    201        /**
    202         * Returns a vector indicating the direction and intensity of fluid flow.
    203         */
    204        private Vec3 getFlowVector(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    205        {
    206            Vec3 var5 = par1IBlockAccess.getWorldVec3Pool().getVecFromPool(0.0D, 0.0D, 0.0D);
    207            int var6 = this.getEffectiveFlowDecay(par1IBlockAccess, par2, par3, par4);
    208
    209            for (int var7 = 0; var7 < 4; ++var7)
    210            {
    211                int var8 = par2;
    212                int var10 = par4;
    213
    214                if (var7 == 0)
    215                {
    216                    var8 = par2 - 1;
    217                }
    218
    219                if (var7 == 1)
    220                {
    221                    var10 = par4 - 1;
    222                }
    223
    224                if (var7 == 2)
    225                {
    226                    ++var8;
    227                }
    228
    229                if (var7 == 3)
    230                {
    231                    ++var10;
    232                }
    233
    234                int var11 = this.getEffectiveFlowDecay(par1IBlockAccess, var8, par3, var10);
    235                int var12;
    236
    237                if (var11 < 0)
    238                {
    239                    if (!par1IBlockAccess.getBlockMaterial(var8, par3, var10).blocksMovement())
    240                    {
    241                        var11 = this.getEffectiveFlowDecay(par1IBlockAccess, var8, par3 - 1, var10);
    242
    243                        if (var11 >= 0)
    244                        {
    245                            var12 = var11 - (var6 - 8);
    246                            var5 = var5.addVector((double)((var8 - par2) * var12), (double)((par3 - par3) * var12), (double)((var10 - par4) * var12));
    247                        }
    248                    }
    249                }
    250                else if (var11 >= 0)
    251                {
    252                    var12 = var11 - var6;
    253                    var5 = var5.addVector((double)((var8 - par2) * var12), (double)((par3 - par3) * var12), (double)((var10 - par4) * var12));
    254                }
    255            }
    256
    257            if (par1IBlockAccess.getBlockMetadata(par2, par3, par4) >= 8)
    258            {
    259                boolean var13 = false;
    260
    261                if (var13 || this.isBlockSolid(par1IBlockAccess, par2, par3, par4 - 1, 2))
    262                {
    263                    var13 = true;
    264                }
    265
    266                if (var13 || this.isBlockSolid(par1IBlockAccess, par2, par3, par4 + 1, 3))
    267                {
    268                    var13 = true;
    269                }
    270
    271                if (var13 || this.isBlockSolid(par1IBlockAccess, par2 - 1, par3, par4, 4))
    272                {
    273                    var13 = true;
    274                }
    275
    276                if (var13 || this.isBlockSolid(par1IBlockAccess, par2 + 1, par3, par4, 5))
    277                {
    278                    var13 = true;
    279                }
    280
    281                if (var13 || this.isBlockSolid(par1IBlockAccess, par2, par3 + 1, par4 - 1, 2))
    282                {
    283                    var13 = true;
    284                }
    285
    286                if (var13 || this.isBlockSolid(par1IBlockAccess, par2, par3 + 1, par4 + 1, 3))
    287                {
    288                    var13 = true;
    289                }
    290
    291                if (var13 || this.isBlockSolid(par1IBlockAccess, par2 - 1, par3 + 1, par4, 4))
    292                {
    293                    var13 = true;
    294                }
    295
    296                if (var13 || this.isBlockSolid(par1IBlockAccess, par2 + 1, par3 + 1, par4, 5))
    297                {
    298                    var13 = true;
    299                }
    300
    301                if (var13)
    302                {
    303                    var5 = var5.normalize().addVector(0.0D, -6.0D, 0.0D);
    304                }
    305            }
    306
    307            var5 = var5.normalize();
    308            return var5;
    309        }
    310
    311        /**
    312         * Can add to the passed in vector for a movement vector to be applied to the entity. Args: x, y, z, entity, vec3d
    313         */
    314        public void velocityToAddToEntity(World par1World, int par2, int par3, int par4, Entity par5Entity, Vec3 par6Vec3)
    315        {
    316            Vec3 var7 = this.getFlowVector(par1World, par2, par3, par4);
    317            par6Vec3.xCoord += var7.xCoord;
    318            par6Vec3.yCoord += var7.yCoord;
    319            par6Vec3.zCoord += var7.zCoord;
    320        }
    321
    322        /**
    323         * How many world ticks before ticking
    324         */
    325        public int tickRate()
    326        {
    327            return this.blockMaterial == Material.water ? 5 : (this.blockMaterial == Material.lava ? 30 : 0);
    328        }
    329
    330        @SideOnly(Side.CLIENT)
    331
    332        /**
    333         * Goes straight to getLightBrightnessForSkyBlocks for Blocks, does some fancy computing for Fluids
    334         */
    335        public int getMixedBrightnessForBlock(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    336        {
    337            int var5 = par1IBlockAccess.getLightBrightnessForSkyBlocks(par2, par3, par4, 0);
    338            int var6 = par1IBlockAccess.getLightBrightnessForSkyBlocks(par2, par3 + 1, par4, 0);
    339            int var7 = var5 & 255;
    340            int var8 = var6 & 255;
    341            int var9 = var5 >> 16 & 255;
    342            int var10 = var6 >> 16 & 255;
    343            return (var7 > var8 ? var7 : var8) | (var9 > var10 ? var9 : var10) << 16;
    344        }
    345
    346        @SideOnly(Side.CLIENT)
    347
    348        /**
    349         * How bright to render this block based on the light its receiving. Args: iBlockAccess, x, y, z
    350         */
    351        public float getBlockBrightness(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    352        {
    353            float var5 = par1IBlockAccess.getLightBrightness(par2, par3, par4);
    354            float var6 = par1IBlockAccess.getLightBrightness(par2, par3 + 1, par4);
    355            return var5 > var6 ? var5 : var6;
    356        }
    357
    358        @SideOnly(Side.CLIENT)
    359
    360        /**
    361         * Returns which pass should this block be rendered on. 0 for solids and 1 for alpha
    362         */
    363        public int getRenderBlockPass()
    364        {
    365            return this.blockMaterial == Material.water ? 1 : 0;
    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            int var6;
    376
    377            if (this.blockMaterial == Material.water)
    378            {
    379                if (par5Random.nextInt(10) == 0)
    380                {
    381                    var6 = par1World.getBlockMetadata(par2, par3, par4);
    382
    383                    if (var6 <= 0 || var6 >= 8)
    384                    {
    385                        par1World.spawnParticle("suspended", (double)((float)par2 + par5Random.nextFloat()), (double)((float)par3 + par5Random.nextFloat()), (double)((float)par4 + par5Random.nextFloat()), 0.0D, 0.0D, 0.0D);
    386                    }
    387                }
    388
    389                for (var6 = 0; var6 < 0; ++var6)
    390                {
    391                    int var7 = par5Random.nextInt(4);
    392                    int var8 = par2;
    393                    int var9 = par4;
    394
    395                    if (var7 == 0)
    396                    {
    397                        var8 = par2 - 1;
    398                    }
    399
    400                    if (var7 == 1)
    401                    {
    402                        ++var8;
    403                    }
    404
    405                    if (var7 == 2)
    406                    {
    407                        var9 = par4 - 1;
    408                    }
    409
    410                    if (var7 == 3)
    411                    {
    412                        ++var9;
    413                    }
    414
    415                    if (par1World.getBlockMaterial(var8, par3, var9) == Material.air && (par1World.getBlockMaterial(var8, par3 - 1, var9).blocksMovement() || par1World.getBlockMaterial(var8, par3 - 1, var9).isLiquid()))
    416                    {
    417                        float var10 = 0.0625F;
    418                        double var11 = (double)((float)par2 + par5Random.nextFloat());
    419                        double var13 = (double)((float)par3 + par5Random.nextFloat());
    420                        double var15 = (double)((float)par4 + par5Random.nextFloat());
    421
    422                        if (var7 == 0)
    423                        {
    424                            var11 = (double)((float)par2 - var10);
    425                        }
    426
    427                        if (var7 == 1)
    428                        {
    429                            var11 = (double)((float)(par2 + 1) + var10);
    430                        }
    431
    432                        if (var7 == 2)
    433                        {
    434                            var15 = (double)((float)par4 - var10);
    435                        }
    436
    437                        if (var7 == 3)
    438                        {
    439                            var15 = (double)((float)(par4 + 1) + var10);
    440                        }
    441
    442                        double var17 = 0.0D;
    443                        double var19 = 0.0D;
    444
    445                        if (var7 == 0)
    446                        {
    447                            var17 = (double)(-var10);
    448                        }
    449
    450                        if (var7 == 1)
    451                        {
    452                            var17 = (double)var10;
    453                        }
    454
    455                        if (var7 == 2)
    456                        {
    457                            var19 = (double)(-var10);
    458                        }
    459
    460                        if (var7 == 3)
    461                        {
    462                            var19 = (double)var10;
    463                        }
    464
    465                        par1World.spawnParticle("splash", var11, var13, var15, var17, 0.0D, var19);
    466                    }
    467                }
    468            }
    469
    470            if (this.blockMaterial == Material.water && par5Random.nextInt(64) == 0)
    471            {
    472                var6 = par1World.getBlockMetadata(par2, par3, par4);
    473
    474                if (var6 > 0 && var6 < 8)
    475                {
    476                    par1World.playSound((double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F), "liquid.water", par5Random.nextFloat() * 0.25F + 0.75F, par5Random.nextFloat() * 1.0F + 0.5F, false);
    477                }
    478            }
    479
    480            double var21;
    481            double var23;
    482            double var22;
    483
    484            if (this.blockMaterial == Material.lava && par1World.getBlockMaterial(par2, par3 + 1, par4) == Material.air && !par1World.isBlockOpaqueCube(par2, par3 + 1, par4))
    485            {
    486                if (par5Random.nextInt(100) == 0)
    487                {
    488                    var21 = (double)((float)par2 + par5Random.nextFloat());
    489                    var22 = (double)par3 + this.maxY;
    490                    var23 = (double)((float)par4 + par5Random.nextFloat());
    491                    par1World.spawnParticle("lava", var21, var22, var23, 0.0D, 0.0D, 0.0D);
    492                    par1World.playSound(var21, var22, var23, "liquid.lavapop", 0.2F + par5Random.nextFloat() * 0.2F, 0.9F + par5Random.nextFloat() * 0.15F, false);
    493                }
    494
    495                if (par5Random.nextInt(200) == 0)
    496                {
    497                    par1World.playSound((double)par2, (double)par3, (double)par4, "liquid.lava", 0.2F + par5Random.nextFloat() * 0.2F, 0.9F + par5Random.nextFloat() * 0.15F, false);
    498                }
    499            }
    500
    501            if (par5Random.nextInt(10) == 0 && par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && !par1World.getBlockMaterial(par2, par3 - 2, par4).blocksMovement())
    502            {
    503                var21 = (double)((float)par2 + par5Random.nextFloat());
    504                var22 = (double)par3 - 1.05D;
    505                var23 = (double)((float)par4 + par5Random.nextFloat());
    506
    507                if (this.blockMaterial == Material.water)
    508                {
    509                    par1World.spawnParticle("dripWater", var21, var22, var23, 0.0D, 0.0D, 0.0D);
    510                }
    511                else
    512                {
    513                    par1World.spawnParticle("dripLava", var21, var22, var23, 0.0D, 0.0D, 0.0D);
    514                }
    515            }
    516        }
    517
    518        @SideOnly(Side.CLIENT)
    519
    520        /**
    521         * the sin and cos of this number determine the surface gradient of the flowing block.
    522         */
    523        public static double getFlowDirection(IBlockAccess par0IBlockAccess, int par1, int par2, int par3, Material par4Material)
    524        {
    525            Vec3 var5 = null;
    526
    527            if (par4Material == Material.water)
    528            {
    529                var5 = ((BlockFluid)Block.waterMoving).getFlowVector(par0IBlockAccess, par1, par2, par3);
    530            }
    531
    532            if (par4Material == Material.lava)
    533            {
    534                var5 = ((BlockFluid)Block.lavaMoving).getFlowVector(par0IBlockAccess, par1, par2, par3);
    535            }
    536
    537            return var5.xCoord == 0.0D && var5.zCoord == 0.0D ? -1000.0D : Math.atan2(var5.zCoord, var5.xCoord) - (Math.PI / 2D);
    538        }
    539
    540        /**
    541         * Called whenever the block is added into the world. Args: world, x, y, z
    542         */
    543        public void onBlockAdded(World par1World, int par2, int par3, int par4)
    544        {
    545            this.checkForHarden(par1World, par2, par3, par4);
    546        }
    547
    548        /**
    549         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
    550         * their own) Args: x, y, z, neighbor blockID
    551         */
    552        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
    553        {
    554            this.checkForHarden(par1World, par2, par3, par4);
    555        }
    556
    557        /**
    558         * Forces lava to check to see if it is colliding with water, and then decide what it should harden to.
    559         */
    560        private void checkForHarden(World par1World, int par2, int par3, int par4)
    561        {
    562            if (par1World.getBlockId(par2, par3, par4) == this.blockID)
    563            {
    564                if (this.blockMaterial == Material.lava)
    565                {
    566                    boolean var5 = false;
    567
    568                    if (var5 || par1World.getBlockMaterial(par2, par3, par4 - 1) == Material.water)
    569                    {
    570                        var5 = true;
    571                    }
    572
    573                    if (var5 || par1World.getBlockMaterial(par2, par3, par4 + 1) == Material.water)
    574                    {
    575                        var5 = true;
    576                    }
    577
    578                    if (var5 || par1World.getBlockMaterial(par2 - 1, par3, par4) == Material.water)
    579                    {
    580                        var5 = true;
    581                    }
    582
    583                    if (var5 || par1World.getBlockMaterial(par2 + 1, par3, par4) == Material.water)
    584                    {
    585                        var5 = true;
    586                    }
    587
    588                    if (var5 || par1World.getBlockMaterial(par2, par3 + 1, par4) == Material.water)
    589                    {
    590                        var5 = true;
    591                    }
    592
    593                    if (var5)
    594                    {
    595                        int var6 = par1World.getBlockMetadata(par2, par3, par4);
    596
    597                        if (var6 == 0)
    598                        {
    599                            par1World.setBlockWithNotify(par2, par3, par4, Block.obsidian.blockID);
    600                        }
    601                        else if (var6 <= 4)
    602                        {
    603                            par1World.setBlockWithNotify(par2, par3, par4, Block.cobblestone.blockID);
    604                        }
    605
    606                        this.triggerLavaMixEffects(par1World, par2, par3, par4);
    607                    }
    608                }
    609            }
    610        }
    611
    612        /**
    613         * Creates fizzing sound and smoke. Used when lava flows over block or mixes with water.
    614         */
    615        protected void triggerLavaMixEffects(World par1World, int par2, int par3, int par4)
    616        {
    617            par1World.playSoundEffect((double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F), "random.fizz", 0.5F, 2.6F + (par1World.rand.nextFloat() - par1World.rand.nextFloat()) * 0.8F);
    618
    619            for (int var5 = 0; var5 < 8; ++var5)
    620            {
    621                par1World.spawnParticle("largesmoke", (double)par2 + Math.random(), (double)par3 + 1.2D, (double)par4 + Math.random(), 0.0D, 0.0D, 0.0D);
    622            }
    623        }
    624    }