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 }