    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    }