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 }