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}