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 = par1IBlockAccess.func_82732_R().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 }