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 }