    001package net.minecraft.block;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.Random;
    006import net.minecraft.block.material.Material;
    007import net.minecraft.entity.Entity;
    008import net.minecraft.util.AxisAlignedBB;
    009import net.minecraft.util.Vec3;
    010import net.minecraft.world.IBlockAccess;
    011import net.minecraft.world.World;
    012
    013public 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}