    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.util.AxisAlignedBB;
    008import net.minecraft.world.IBlockAccess;
    009import net.minecraft.world.World;
    010import net.minecraft.world.WorldProviderEnd;
    011
    012import net.minecraftforge.common.ForgeDirection;
    013import static net.minecraftforge.common.ForgeDirection.*;
    014
    015public 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}