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.util.AxisAlignedBB; 008 import net.minecraft.world.IBlockAccess; 009 import net.minecraft.world.World; 010 import net.minecraft.world.WorldProviderEnd; 011 012 import net.minecraftforge.common.ForgeDirection; 013 import static net.minecraftforge.common.ForgeDirection.*; 014 015 public class BlockFire extends Block 016 { 017 /** The chance this block will encourage nearby blocks to catch on fire */ 018 private int[] chanceToEncourageFire = new int[256]; 019 020 /** 021 * This is an array indexed by block ID the larger the number in the array the more likely a block type will catch 022 * fires 023 */ 024 private int[] abilityToCatchFire = new int[256]; 025 026 protected BlockFire(int par1, int par2) 027 { 028 super(par1, par2, Material.fire); 029 this.setTickRandomly(true); 030 } 031 032 /** 033 * This method is called on a block after all other blocks gets already created. You can use it to reference and 034 * configure something on the block that needs the others ones. 035 */ 036 public void initializeBlock() 037 { 038 abilityToCatchFire = Block.blockFlammability; 039 chanceToEncourageFire = Block.blockFireSpreadSpeed; 040 this.setBurnRate(Block.planks.blockID, 5, 20); 041 this.setBurnRate(Block.woodDoubleSlab.blockID, 5, 20); 042 this.setBurnRate(Block.woodSingleSlab.blockID, 5, 20); 043 this.setBurnRate(Block.fence.blockID, 5, 20); 044 this.setBurnRate(Block.stairCompactPlanks.blockID, 5, 20); 045 this.setBurnRate(Block.stairsWoodBirch.blockID, 5, 20); 046 this.setBurnRate(Block.stairsWoodSpruce.blockID, 5, 20); 047 this.setBurnRate(Block.stairsWoodJungle.blockID, 5, 20); 048 this.setBurnRate(Block.wood.blockID, 5, 5); 049 this.setBurnRate(Block.leaves.blockID, 30, 60); 050 this.setBurnRate(Block.bookShelf.blockID, 30, 20); 051 this.setBurnRate(Block.tnt.blockID, 15, 100); 052 this.setBurnRate(Block.tallGrass.blockID, 60, 100); 053 this.setBurnRate(Block.cloth.blockID, 30, 60); 054 this.setBurnRate(Block.vine.blockID, 15, 100); 055 } 056 057 /** 058 * Sets the burn rate for a block. The larger abilityToCatchFire the more easily it will catch. The larger 059 * chanceToEncourageFire the faster it will burn and spread to other blocks. Args: blockID, chanceToEncourageFire, 060 * abilityToCatchFire 061 */ 062 private void setBurnRate(int par1, int par2, int par3) 063 { 064 Block.setBurnProperties(par1, par2, par3); 065 } 066 067 /** 068 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been 069 * cleared to be reused) 070 */ 071 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) 072 { 073 return null; 074 } 075 076 /** 077 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 078 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 079 */ 080 public boolean isOpaqueCube() 081 { 082 return false; 083 } 084 085 /** 086 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 087 */ 088 public boolean renderAsNormalBlock() 089 { 090 return false; 091 } 092 093 /** 094 * The type of render function that is called for this block 095 */ 096 public int getRenderType() 097 { 098 return 3; 099 } 100 101 /** 102 * Returns the quantity of items to drop on block destruction. 103 */ 104 public int quantityDropped(Random par1Random) 105 { 106 return 0; 107 } 108 109 /** 110 * How many world ticks before ticking 111 */ 112 public int tickRate() 113 { 114 return 30; 115 } 116 117 /** 118 * Ticks the block if it's been scheduled 119 */ 120 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) 121 { 122 if (par1World.getGameRules().getGameRuleBooleanValue("doFireTick")) 123 { 124 Block base = Block.blocksList[par1World.getBlockId(par2, par3 - 1, par4)]; 125 boolean var6 = (base != null && base.isFireSource(par1World, par2, par3 - 1, par4, par1World.getBlockMetadata(par2, par3 - 1, par4), UP)); 126 127 if (!this.canPlaceBlockAt(par1World, par2, par3, par4)) 128 { 129 par1World.setBlockWithNotify(par2, par3, par4, 0); 130 } 131 132 if (!var6 && par1World.isRaining() && (par1World.canLightningStrikeAt(par2, par3, par4) || par1World.canLightningStrikeAt(par2 - 1, par3, par4) || par1World.canLightningStrikeAt(par2 + 1, par3, par4) || par1World.canLightningStrikeAt(par2, par3, par4 - 1) || par1World.canLightningStrikeAt(par2, par3, par4 + 1))) 133 { 134 par1World.setBlockWithNotify(par2, par3, par4, 0); 135 } 136 else 137 { 138 int var7 = par1World.getBlockMetadata(par2, par3, par4); 139 140 if (var7 < 15) 141 { 142 par1World.setBlockMetadata(par2, par3, par4, var7 + par5Random.nextInt(3) / 2); 143 } 144 145 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate() + par5Random.nextInt(10)); 146 147 if (!var6 && !this.canNeighborBurn(par1World, par2, par3, par4)) 148 { 149 if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) || var7 > 3) 150 { 151 par1World.setBlockWithNotify(par2, par3, par4, 0); 152 } 153 } 154 else if (!var6 && !this.canBlockCatchFire(par1World, par2, par3 - 1, par4, UP) && var7 == 15 && par5Random.nextInt(4) == 0) 155 { 156 par1World.setBlockWithNotify(par2, par3, par4, 0); 157 } 158 else 159 { 160 boolean var8 = par1World.isBlockHighHumidity(par2, par3, par4); 161 byte var9 = 0; 162 163 if (var8) 164 { 165 var9 = -50; 166 } 167 168 this.tryToCatchBlockOnFire(par1World, par2 + 1, par3, par4, 300 + var9, par5Random, var7, WEST ); 169 this.tryToCatchBlockOnFire(par1World, par2 - 1, par3, par4, 300 + var9, par5Random, var7, EAST ); 170 this.tryToCatchBlockOnFire(par1World, par2, par3 - 1, par4, 250 + var9, par5Random, var7, UP ); 171 this.tryToCatchBlockOnFire(par1World, par2, par3 + 1, par4, 250 + var9, par5Random, var7, DOWN ); 172 this.tryToCatchBlockOnFire(par1World, par2, par3, par4 - 1, 300 + var9, par5Random, var7, SOUTH); 173 this.tryToCatchBlockOnFire(par1World, par2, par3, par4 + 1, 300 + var9, par5Random, var7, NORTH); 174 175 for (int var10 = par2 - 1; var10 <= par2 + 1; ++var10) 176 { 177 for (int var11 = par4 - 1; var11 <= par4 + 1; ++var11) 178 { 179 for (int var12 = par3 - 1; var12 <= par3 + 4; ++var12) 180 { 181 if (var10 != par2 || var12 != par3 || var11 != par4) 182 { 183 int var13 = 100; 184 185 if (var12 > par3 + 1) 186 { 187 var13 += (var12 - (par3 + 1)) * 100; 188 } 189 190 int var14 = this.getChanceOfNeighborsEncouragingFire(par1World, var10, var12, var11); 191 192 if (var14 > 0) 193 { 194 int var15 = (var14 + 40 + par1World.difficultySetting * 7) / (var7 + 30); 195 196 if (var8) 197 { 198 var15 /= 2; 199 } 200 201 if (var15 > 0 && par5Random.nextInt(var13) <= var15 && (!par1World.isRaining() || !par1World.canLightningStrikeAt(var10, var12, var11)) && !par1World.canLightningStrikeAt(var10 - 1, var12, par4) && !par1World.canLightningStrikeAt(var10 + 1, var12, var11) && !par1World.canLightningStrikeAt(var10, var12, var11 - 1) && !par1World.canLightningStrikeAt(var10, var12, var11 + 1)) 202 { 203 int var16 = var7 + par5Random.nextInt(5) / 4; 204 205 if (var16 > 15) 206 { 207 var16 = 15; 208 } 209 210 par1World.setBlockAndMetadataWithNotify(var10, var12, var11, this.blockID, var16); 211 } 212 } 213 } 214 } 215 } 216 } 217 } 218 } 219 } 220 } 221 222 public boolean func_82506_l() 223 { 224 return false; 225 } 226 227 @Deprecated 228 private void tryToCatchBlockOnFire(World par1World, int par2, int par3, int par4, int par5, Random par6Random, int par7) 229 { 230 tryToCatchBlockOnFire(par1World, par2, par3, par4, par5, par6Random, par7, UP); 231 } 232 233 private void tryToCatchBlockOnFire(World par1World, int par2, int par3, int par4, int par5, Random par6Random, int par7, ForgeDirection face) 234 { 235 int var8 = 0; 236 Block block = Block.blocksList[par1World.getBlockId(par2, par3, par4)]; 237 if (block != null) 238 { 239 var8 = block.getFlammability(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), face); 240 } 241 242 if (par6Random.nextInt(par5) < var8) 243 { 244 boolean var9 = par1World.getBlockId(par2, par3, par4) == Block.tnt.blockID; 245 246 if (par6Random.nextInt(par7 + 10) < 5 && !par1World.canLightningStrikeAt(par2, par3, par4)) 247 { 248 int var10 = par7 + par6Random.nextInt(5) / 4; 249 250 if (var10 > 15) 251 { 252 var10 = 15; 253 } 254 255 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, this.blockID, var10); 256 } 257 else 258 { 259 par1World.setBlockWithNotify(par2, par3, par4, 0); 260 } 261 262 if (var9) 263 { 264 Block.tnt.onBlockDestroyedByPlayer(par1World, par2, par3, par4, 1); 265 } 266 } 267 } 268 269 /** 270 * Returns true if at least one block next to this one can burn. 271 */ 272 private boolean canNeighborBurn(World par1World, int par2, int par3, int par4) 273 { 274 return canBlockCatchFire(par1World, par2 + 1, par3, par4, WEST ) || 275 canBlockCatchFire(par1World, par2 - 1, par3, par4, EAST ) || 276 canBlockCatchFire(par1World, par2, par3 - 1, par4, UP ) || 277 canBlockCatchFire(par1World, par2, par3 + 1, par4, DOWN ) || 278 canBlockCatchFire(par1World, par2, par3, par4 - 1, SOUTH) || 279 canBlockCatchFire(par1World, par2, par3, par4 + 1, NORTH); 280 } 281 282 /** 283 * Gets the highest chance of a neighbor block encouraging this block to catch fire 284 */ 285 private int getChanceOfNeighborsEncouragingFire(World par1World, int par2, int par3, int par4) 286 { 287 byte var5 = 0; 288 289 if (!par1World.isAirBlock(par2, par3, par4)) 290 { 291 return 0; 292 } 293 else 294 { 295 int var6 = this.getChanceToEncourageFire(par1World, par2 + 1, par3, par4, var5, WEST); 296 var6 = this.getChanceToEncourageFire(par1World, par2 - 1, par3, par4, var6, EAST); 297 var6 = this.getChanceToEncourageFire(par1World, par2, par3 - 1, par4, var6, UP); 298 var6 = this.getChanceToEncourageFire(par1World, par2, par3 + 1, par4, var6, DOWN); 299 var6 = this.getChanceToEncourageFire(par1World, par2, par3, par4 - 1, var6, SOUTH); 300 var6 = this.getChanceToEncourageFire(par1World, par2, par3, par4 + 1, var6, NORTH); 301 return var6; 302 } 303 } 304 305 /** 306 * Returns if this block is collidable (only used by Fire). Args: x, y, z 307 */ 308 public boolean isCollidable() 309 { 310 return false; 311 } 312 313 /** 314 * Checks the specified block coordinate to see if it can catch fire. Args: blockAccess, x, y, z 315 * Deprecated for a side-sensitive version 316 */ 317 @Deprecated 318 public boolean canBlockCatchFire(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 319 { 320 return canBlockCatchFire(par1IBlockAccess, par2, par3, par4, UP); 321 } 322 323 /** 324 * Retrieves a specified block's chance to encourage their neighbors to burn and if the number is greater than the 325 * current number passed in it will return its number instead of the passed in one. Args: world, x, y, z, 326 * curChanceToEncourageFire 327 * Deprecated for a side-sensitive version 328 */ 329 @Deprecated 330 public int getChanceToEncourageFire(World par1World, int par2, int par3, int par4, int par5) 331 { 332 return getChanceToEncourageFire(par1World, par2, par3, par4, par5, UP); 333 } 334 335 /** 336 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 337 */ 338 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 339 { 340 return par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) || this.canNeighborBurn(par1World, par2, par3, par4); 341 } 342 343 /** 344 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 345 * their own) Args: x, y, z, neighbor blockID 346 */ 347 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 348 { 349 if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && !this.canNeighborBurn(par1World, par2, par3, par4)) 350 { 351 par1World.setBlockWithNotify(par2, par3, par4, 0); 352 } 353 } 354 355 /** 356 * Called whenever the block is added into the world. Args: world, x, y, z 357 */ 358 public void onBlockAdded(World par1World, int par2, int par3, int par4) 359 { 360 if (par1World.provider.dimensionId > 0 || par1World.getBlockId(par2, par3 - 1, par4) != Block.obsidian.blockID || !Block.portal.tryToCreatePortal(par1World, par2, par3, par4)) 361 { 362 if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && !this.canNeighborBurn(par1World, par2, par3, par4)) 363 { 364 par1World.setBlockWithNotify(par2, par3, par4, 0); 365 } 366 else 367 { 368 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate() + par1World.rand.nextInt(10)); 369 } 370 } 371 } 372 373 @SideOnly(Side.CLIENT) 374 375 /** 376 * A randomly called display update to be able to add particles or other items for display 377 */ 378 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random) 379 { 380 if (par5Random.nextInt(24) == 0) 381 { 382 par1World.playSound((double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F), "fire.fire", 1.0F + par5Random.nextFloat(), par5Random.nextFloat() * 0.7F + 0.3F, false); 383 } 384 385 int var6; 386 float var7; 387 float var8; 388 float var9; 389 390 if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && !Block.fire.canBlockCatchFire(par1World, par2, par3 - 1, par4, UP)) 391 { 392 if (Block.fire.canBlockCatchFire(par1World, par2 - 1, par3, par4, EAST)) 393 { 394 for (var6 = 0; var6 < 2; ++var6) 395 { 396 var7 = (float)par2 + par5Random.nextFloat() * 0.1F; 397 var8 = (float)par3 + par5Random.nextFloat(); 398 var9 = (float)par4 + par5Random.nextFloat(); 399 par1World.spawnParticle("largesmoke", (double)var7, (double)var8, (double)var9, 0.0D, 0.0D, 0.0D); 400 } 401 } 402 403 if (Block.fire.canBlockCatchFire(par1World, par2 + 1, par3, par4, WEST)) 404 { 405 for (var6 = 0; var6 < 2; ++var6) 406 { 407 var7 = (float)(par2 + 1) - par5Random.nextFloat() * 0.1F; 408 var8 = (float)par3 + par5Random.nextFloat(); 409 var9 = (float)par4 + par5Random.nextFloat(); 410 par1World.spawnParticle("largesmoke", (double)var7, (double)var8, (double)var9, 0.0D, 0.0D, 0.0D); 411 } 412 } 413 414 if (Block.fire.canBlockCatchFire(par1World, par2, par3, par4 - 1, SOUTH)) 415 { 416 for (var6 = 0; var6 < 2; ++var6) 417 { 418 var7 = (float)par2 + par5Random.nextFloat(); 419 var8 = (float)par3 + par5Random.nextFloat(); 420 var9 = (float)par4 + par5Random.nextFloat() * 0.1F; 421 par1World.spawnParticle("largesmoke", (double)var7, (double)var8, (double)var9, 0.0D, 0.0D, 0.0D); 422 } 423 } 424 425 if (Block.fire.canBlockCatchFire(par1World, par2, par3, par4 + 1, NORTH)) 426 { 427 for (var6 = 0; var6 < 2; ++var6) 428 { 429 var7 = (float)par2 + par5Random.nextFloat(); 430 var8 = (float)par3 + par5Random.nextFloat(); 431 var9 = (float)(par4 + 1) - par5Random.nextFloat() * 0.1F; 432 par1World.spawnParticle("largesmoke", (double)var7, (double)var8, (double)var9, 0.0D, 0.0D, 0.0D); 433 } 434 } 435 436 if (Block.fire.canBlockCatchFire(par1World, par2, par3 + 1, par4, DOWN)) 437 { 438 for (var6 = 0; var6 < 2; ++var6) 439 { 440 var7 = (float)par2 + par5Random.nextFloat(); 441 var8 = (float)(par3 + 1) - par5Random.nextFloat() * 0.1F; 442 var9 = (float)par4 + par5Random.nextFloat(); 443 par1World.spawnParticle("largesmoke", (double)var7, (double)var8, (double)var9, 0.0D, 0.0D, 0.0D); 444 } 445 } 446 } 447 else 448 { 449 for (var6 = 0; var6 < 3; ++var6) 450 { 451 var7 = (float)par2 + par5Random.nextFloat(); 452 var8 = (float)par3 + par5Random.nextFloat() * 0.5F + 0.5F; 453 var9 = (float)par4 + par5Random.nextFloat(); 454 par1World.spawnParticle("largesmoke", (double)var7, (double)var8, (double)var9, 0.0D, 0.0D, 0.0D); 455 } 456 } 457 } 458 459 /** 460 * Side sensitive version that calls the block function. 461 * 462 * @param world The current world 463 * @param x X Position 464 * @param y Y Position 465 * @param z Z Position 466 * @param face The side the fire is coming from 467 * @return True if the face can catch fire. 468 */ 469 public boolean canBlockCatchFire(IBlockAccess world, int x, int y, int z, ForgeDirection face) 470 { 471 Block block = Block.blocksList[world.getBlockId(x, y, z)]; 472 if (block != null) 473 { 474 return block.isFlammable(world, x, y, z, world.getBlockMetadata(x, y, z), face); 475 } 476 return false; 477 } 478 479 /** 480 * Side sensitive version that calls the block function. 481 * 482 * @param world The current world 483 * @param x X Position 484 * @param y Y Position 485 * @param z Z Position 486 * @param oldChance The previous maximum chance. 487 * @param face The side the fire is coming from 488 * @return The chance of the block catching fire, or oldChance if it is higher 489 */ 490 public int getChanceToEncourageFire(World world, int x, int y, int z, int oldChance, ForgeDirection face) 491 { 492 int newChance = 0; 493 Block block = Block.blocksList[world.getBlockId(x, y, z)]; 494 if (block != null) 495 { 496 newChance = block.getFireSpreadSpeed(world, x, y, z, world.getBlockMetadata(x, y, z), face); 497 } 498 return (newChance > oldChance ? newChance : oldChance); 499 } 500 }