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 }