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