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    }