    001package net.minecraft.block;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.ArrayList;
    006import java.util.HashMap;
    007import java.util.List;
    008import java.util.Map;
    009import java.util.Random;
    010import net.minecraft.client.renderer.texture.IconRegister;
    011import net.minecraft.creativetab.CreativeTabs;
    012import net.minecraft.world.IBlockAccess;
    013import net.minecraft.world.World;
    014
    015public class BlockRedstoneTorch extends BlockTorch
    016{
    017    /** Whether the redstone torch is currently active or not. */
    018    private boolean torchActive = false;
    019
    020    /** Map of ArrayLists of RedstoneUpdateInfo. Key of map is World. */
    021    private static Map redstoneUpdateInfoCache = new HashMap();
    022
    023    private boolean checkForBurnout(World par1World, int par2, int par3, int par4, boolean par5)
    024    {
    025        if (!redstoneUpdateInfoCache.containsKey(par1World))
    026        {
    027            redstoneUpdateInfoCache.put(par1World, new ArrayList());
    028        }
    029
    030        List list = (List)redstoneUpdateInfoCache.get(par1World);
    031
    032        if (par5)
    033        {
    034            list.add(new RedstoneUpdateInfo(par2, par3, par4, par1World.getTotalWorldTime()));
    035        }
    036
    037        int l = 0;
    038
    039        for (int i1 = 0; i1 < list.size(); ++i1)
    040        {
    041            RedstoneUpdateInfo redstoneupdateinfo = (RedstoneUpdateInfo)list.get(i1);
    042
    043            if (redstoneupdateinfo.x == par2 && redstoneupdateinfo.y == par3 && redstoneupdateinfo.z == par4)
    044            {
    045                ++l;
    046
    047                if (l >= 8)
    048                {
    049                    return true;
    050                }
    051            }
    052        }
    053
    054        return false;
    055    }
    056
    057    protected BlockRedstoneTorch(int par1, boolean par2)
    058    {
    059        super(par1);
    060        this.torchActive = par2;
    061        this.setTickRandomly(true);
    062        this.setCreativeTab((CreativeTabs)null);
    063    }
    064
    065    /**
    066     * How many world ticks before ticking
    067     */
    068    public int tickRate(World par1World)
    069    {
    070        return 2;
    071    }
    072
    073    /**
    074     * Called whenever the block is added into the world. Args: world, x, y, z
    075     */
    076    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    077    {
    078        if (par1World.getBlockMetadata(par2, par3, par4) == 0)
    079        {
    080            super.onBlockAdded(par1World, par2, par3, par4);
    081        }
    082
    083        if (this.torchActive)
    084        {
    085            par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
    086            par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
    087            par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
    088            par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
    089            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
    090            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
    091        }
    092    }
    093
    094    /**
    095     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
    096     */
    097    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
    098    {
    099        if (this.torchActive)
    100        {
    101            par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
    102            par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
    103            par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
    104            par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
    105            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
    106            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
    107        }
    108    }
    109
    110    /**
    111     * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube
    112     * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X,
    113     * Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
    114     */
    115    public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    116    {
    117        if (!this.torchActive)
    118        {
    119            return 0;
    120        }
    121        else
    122        {
    123            int i1 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
    124            return i1 == 5 && par5 == 1 ? 0 : (i1 == 3 && par5 == 3 ? 0 : (i1 == 4 && par5 == 2 ? 0 : (i1 == 1 && par5 == 5 ? 0 : (i1 == 2 && par5 == 4 ? 0 : 15))));
    125        }
    126    }
    127
    128    /**
    129     * Returns true or false based on whether the block the torch is attached to is providing indirect power.
    130     */
    131    private boolean isIndirectlyPowered(World par1World, int par2, int par3, int par4)
    132    {
    133        int l = par1World.getBlockMetadata(par2, par3, par4);
    134        return l == 5 && par1World.getIndirectPowerOutput(par2, par3 - 1, par4, 0) ? true : (l == 3 && par1World.getIndirectPowerOutput(par2, par3, par4 - 1, 2) ? true : (l == 4 && par1World.getIndirectPowerOutput(par2, par3, par4 + 1, 3) ? true : (l == 1 && par1World.getIndirectPowerOutput(par2 - 1, par3, par4, 4) ? true : l == 2 && par1World.getIndirectPowerOutput(par2 + 1, par3, par4, 5))));
    135    }
    136
    137    /**
    138     * Ticks the block if it's been scheduled
    139     */
    140    public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
    141    {
    142        boolean flag = this.isIndirectlyPowered(par1World, par2, par3, par4);
    143        List list = (List)redstoneUpdateInfoCache.get(par1World);
    144
    145        while (list != null && !list.isEmpty() && par1World.getTotalWorldTime() - ((RedstoneUpdateInfo)list.get(0)).updateTime > 60L)
    146        {
    147            list.remove(0);
    148        }
    149
    150        if (this.torchActive)
    151        {
    152            if (flag)
    153            {
    154                par1World.setBlock(par2, par3, par4, Block.torchRedstoneIdle.blockID, par1World.getBlockMetadata(par2, par3, par4), 3);
    155
    156                if (this.checkForBurnout(par1World, par2, par3, par4, true))
    157                {
    158                    par1World.playSoundEffect((double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F), "random.fizz", 0.5F, 2.6F + (par1World.rand.nextFloat() - par1World.rand.nextFloat()) * 0.8F);
    159
    160                    for (int l = 0; l < 5; ++l)
    161                    {
    162                        double d0 = (double)par2 + par5Random.nextDouble() * 0.6D + 0.2D;
    163                        double d1 = (double)par3 + par5Random.nextDouble() * 0.6D + 0.2D;
    164                        double d2 = (double)par4 + par5Random.nextDouble() * 0.6D + 0.2D;
    165                        par1World.spawnParticle("smoke", d0, d1, d2, 0.0D, 0.0D, 0.0D);
    166                    }
    167                }
    168            }
    169        }
    170        else if (!flag && !this.checkForBurnout(par1World, par2, par3, par4, false))
    171        {
    172            par1World.setBlock(par2, par3, par4, Block.torchRedstoneActive.blockID, par1World.getBlockMetadata(par2, par3, par4), 3);
    173        }
    174    }
    175
    176    /**
    177     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
    178     * their own) Args: x, y, z, neighbor blockID
    179     */
    180    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
    181    {
    182        if (!this.func_94397_d(par1World, par2, par3, par4, par5))
    183        {
    184            boolean flag = this.isIndirectlyPowered(par1World, par2, par3, par4);
    185
    186            if (this.torchActive && flag || !this.torchActive && !flag)
    187            {
    188                par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate(par1World));
    189            }
    190        }
    191    }
    192
    193    /**
    194     * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z,
    195     * side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
    196     */
    197    public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    198    {
    199        return par5 == 0 ? this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5) : 0;
    200    }
    201
    202    /**
    203     * Returns the ID of the items to drop on destruction.
    204     */
    205    public int idDropped(int par1, Random par2Random, int par3)
    206    {
    207        return Block.torchRedstoneActive.blockID;
    208    }
    209
    210    /**
    211     * Can this block provide power. Only wire currently seems to have this change based on its state.
    212     */
    213    public boolean canProvidePower()
    214    {
    215        return true;
    216    }
    217
    218    @SideOnly(Side.CLIENT)
    219
    220    /**
    221     * A randomly called display update to be able to add particles or other items for display
    222     */
    223    public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
    224    {
    225        if (this.torchActive)
    226        {
    227            int l = par1World.getBlockMetadata(par2, par3, par4);
    228            double d0 = (double)((float)par2 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    229            double d1 = (double)((float)par3 + 0.7F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    230            double d2 = (double)((float)par4 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
    231            double d3 = 0.2199999988079071D;
    232            double d4 = 0.27000001072883606D;
    233
    234            if (l == 1)
    235            {
    236                par1World.spawnParticle("reddust", d0 - d4, d1 + d3, d2, 0.0D, 0.0D, 0.0D);
    237            }
    238            else if (l == 2)
    239            {
    240                par1World.spawnParticle("reddust", d0 + d4, d1 + d3, d2, 0.0D, 0.0D, 0.0D);
    241            }
    242            else if (l == 3)
    243            {
    244                par1World.spawnParticle("reddust", d0, d1 + d3, d2 - d4, 0.0D, 0.0D, 0.0D);
    245            }
    246            else if (l == 4)
    247            {
    248                par1World.spawnParticle("reddust", d0, d1 + d3, d2 + d4, 0.0D, 0.0D, 0.0D);
    249            }
    250            else
    251            {
    252                par1World.spawnParticle("reddust", d0, d1, d2, 0.0D, 0.0D, 0.0D);
    253            }
    254        }
    255    }
    256
    257    @SideOnly(Side.CLIENT)
    258
    259    /**
    260     * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
    261     */
    262    public int idPicked(World par1World, int par2, int par3, int par4)
    263    {
    264        return Block.torchRedstoneActive.blockID;
    265    }
    266
    267    /**
    268     * Returns true if the given block ID is equivalent to this one. Example: redstoneTorchOn matches itself and
    269     * redstoneTorchOff, and vice versa. Most blocks only match themselves.
    270     */
    271    public boolean isAssociatedBlockID(int par1)
    272    {
    273        return par1 == Block.torchRedstoneIdle.blockID || par1 == Block.torchRedstoneActive.blockID;
    274    }
    275
    276    @SideOnly(Side.CLIENT)
    277
    278    /**
    279     * When this method is called, your block should register all the icons it needs with the given IconRegister. This
    280     * is the only chance you get to register icons.
    281     */
    282    public void registerIcons(IconRegister par1IconRegister)
    283    {
    284        if (this.torchActive)
    285        {
    286            this.blockIcon = par1IconRegister.registerIcon("redtorch_lit");
    287        }
    288        else
    289        {
    290            this.blockIcon = par1IconRegister.registerIcon("redtorch");
    291        }
    292    }
    293}