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