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 }