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