001package net.minecraft.block;
002
003import java.util.Random;
004import net.minecraft.block.material.Material;
005import net.minecraft.creativetab.CreativeTabs;
006import net.minecraft.util.AxisAlignedBB;
007import net.minecraft.util.Direction;
008import net.minecraft.world.IBlockAccess;
009import net.minecraft.world.World;
010
011import net.minecraftforge.common.ForgeDirection;
012import static net.minecraftforge.common.ForgeDirection.*;
013
014public class BlockTripWireSource extends Block
015{
016    public BlockTripWireSource(int par1)
017    {
018        super(par1, Material.circuits);
019        this.setCreativeTab(CreativeTabs.tabRedstone);
020        this.setTickRandomly(true);
021    }
022
023    /**
024     * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
025     * cleared to be reused)
026     */
027    public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
028    {
029        return null;
030    }
031
032    /**
033     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
034     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
035     */
036    public boolean isOpaqueCube()
037    {
038        return false;
039    }
040
041    /**
042     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
043     */
044    public boolean renderAsNormalBlock()
045    {
046        return false;
047    }
048
049    /**
050     * The type of render function that is called for this block
051     */
052    public int getRenderType()
053    {
054        return 29;
055    }
056
057    /**
058     * How many world ticks before ticking
059     */
060    public int tickRate(World par1World)
061    {
062        return 10;
063    }
064
065    /**
066     * checks to see if you can place this block can be placed on that side of a block: BlockLever overrides
067     */
068    public boolean canPlaceBlockOnSide(World par1World, int par2, int par3, int par4, int par5)
069    {
070        ForgeDirection dir = ForgeDirection.getOrientation(par5);
071        return (dir == NORTH && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH)) ||
072               (dir == SOUTH && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH)) ||
073               (dir == WEST  && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST )) ||
074               (dir == EAST  && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST ));
075    }
076
077    /**
078     * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
079     */
080    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
081    {
082        return par1World.isBlockSolidOnSide(par2 - 1, par3, par4, SOUTH) ||
083               par1World.isBlockSolidOnSide(par2 + 1, par3, par4, NORTH) ||
084               par1World.isBlockSolidOnSide(par2, par3, par4 - 1, EAST ) ||
085               par1World.isBlockSolidOnSide(par2, par3, par4 + 1, WEST );
086    }
087
088    /**
089     * Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata
090     */
091    public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9)
092    {
093        byte b0 = 0;
094
095        if (par5 == 2 && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, WEST, true))
096        {
097            b0 = 2;
098        }
099
100        if (par5 == 3 && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, EAST, true))
101        {
102            b0 = 0;
103        }
104
105        if (par5 == 4 && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, NORTH, true))
106        {
107            b0 = 1;
108        }
109
110        if (par5 == 5 && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, SOUTH, true))
111        {
112            b0 = 3;
113        }
114
115        return b0;
116    }
117
118    /**
119     * Called after a block is placed
120     */
121    public void onPostBlockPlaced(World par1World, int par2, int par3, int par4, int par5)
122    {
123        this.func_72143_a(par1World, par2, par3, par4, this.blockID, par5, false, -1, 0);
124    }
125
126    /**
127     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
128     * their own) Args: x, y, z, neighbor blockID
129     */
130    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
131    {
132        if (par5 != this.blockID)
133        {
134            if (this.func_72144_l(par1World, par2, par3, par4))
135            {
136                int i1 = par1World.getBlockMetadata(par2, par3, par4);
137                int j1 = i1 & 3;
138                boolean flag = false;
139
140                if (!par1World.isBlockSolidOnSide(par2 - 1, par3, par4, SOUTH) && j1 == 3)
141                {
142                    flag = true;
143                }
144
145                if (!par1World.isBlockSolidOnSide(par2 + 1, par3, par4, NORTH) && j1 == 1)
146                {
147                    flag = true;
148                }
149
150                if (!par1World.isBlockSolidOnSide(par2, par3, par4 - 1, EAST) && j1 == 0)
151                {
152                    flag = true;
153                }
154
155                if (!par1World.isBlockSolidOnSide(par2, par3, par4 + 1, WEST) && j1 == 2)
156                {
157                    flag = true;
158                }
159
160                if (flag)
161                {
162                    this.dropBlockAsItem(par1World, par2, par3, par4, i1, 0);
163                    par1World.func_94571_i(par2, par3, par4);
164                }
165            }
166        }
167    }
168
169    public void func_72143_a(World par1World, int par2, int par3, int par4, int par5, int par6, boolean par7, int par8, int par9)
170    {
171        int l1 = par6 & 3;
172        boolean flag1 = (par6 & 4) == 4;
173        boolean flag2 = (par6 & 8) == 8;
174        boolean flag3 = par5 == Block.tripWireSource.blockID;
175        boolean flag4 = false;
176        boolean flag5 = !par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP);
177        int i2 = Direction.offsetX[l1];
178        int j2 = Direction.offsetZ[l1];
179        int k2 = 0;
180        int[] aint = new int[42];
181        int l2;
182        int i3;
183        int j3;
184        int k3;
185        int l3;
186
187        for (i3 = 1; i3 < 42; ++i3)
188        {
189            l2 = par2 + i2 * i3;
190            k3 = par4 + j2 * i3;
191            j3 = par1World.getBlockId(l2, par3, k3);
192
193            if (j3 == Block.tripWireSource.blockID)
194            {
195                l3 = par1World.getBlockMetadata(l2, par3, k3);
196
197                if ((l3 & 3) == Direction.footInvisibleFaceRemap[l1])
198                {
199                    k2 = i3;
200                }
201
202                break;
203            }
204
205            if (j3 != Block.tripWire.blockID && i3 != par8)
206            {
207                aint[i3] = -1;
208                flag3 = false;
209            }
210            else
211            {
212                l3 = i3 == par8 ? par9 : par1World.getBlockMetadata(l2, par3, k3);
213                boolean flag6 = (l3 & 8) != 8;
214                boolean flag7 = (l3 & 1) == 1;
215                boolean flag8 = (l3 & 2) == 2;
216                flag3 &= flag8 == flag5;
217                flag4 |= flag6 && flag7;
218                aint[i3] = l3;
219
220                if (i3 == par8)
221                {
222                    par1World.scheduleBlockUpdate(par2, par3, par4, par5, this.tickRate(par1World));
223                    flag3 &= flag6;
224                }
225            }
226        }
227
228        flag3 &= k2 > 1;
229        flag4 &= flag3;
230        i3 = (flag3 ? 4 : 0) | (flag4 ? 8 : 0);
231        par6 = l1 | i3;
232
233        if (k2 > 0)
234        {
235            l2 = par2 + i2 * k2;
236            k3 = par4 + j2 * k2;
237            j3 = Direction.footInvisibleFaceRemap[l1];
238            par1World.setBlockMetadataWithNotify(l2, par3, k3, j3 | i3, 3);
239            this.notifyNeighborOfChange(par1World, l2, par3, k3, j3);
240            this.playSoundEffect(par1World, l2, par3, k3, flag3, flag4, flag1, flag2);
241        }
242
243        this.playSoundEffect(par1World, par2, par3, par4, flag3, flag4, flag1, flag2);
244
245        if (par5 > 0)
246        {
247            par1World.setBlockMetadataWithNotify(par2, par3, par4, par6, 3);
248
249            if (par7)
250            {
251                this.notifyNeighborOfChange(par1World, par2, par3, par4, l1);
252            }
253        }
254
255        if (flag1 != flag3)
256        {
257            for (l2 = 1; l2 < k2; ++l2)
258            {
259                k3 = par2 + i2 * l2;
260                j3 = par4 + j2 * l2;
261                l3 = aint[l2];
262
263                if (l3 >= 0)
264                {
265                    if (flag3)
266                    {
267                        l3 |= 4;
268                    }
269                    else
270                    {
271                        l3 &= -5;
272                    }
273
274                    par1World.setBlockMetadataWithNotify(k3, par3, j3, l3, 3);
275                }
276            }
277        }
278    }
279
280    /**
281     * Ticks the block if it's been scheduled
282     */
283    public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
284    {
285        this.func_72143_a(par1World, par2, par3, par4, this.blockID, par1World.getBlockMetadata(par2, par3, par4), true, -1, 0);
286    }
287
288    /**
289     * only of the conditions are right
290     */
291    private void playSoundEffect(World par1World, int par2, int par3, int par4, boolean par5, boolean par6, boolean par7, boolean par8)
292    {
293        if (par6 && !par8)
294        {
295            par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.1D, (double)par4 + 0.5D, "random.click", 0.4F, 0.6F);
296        }
297        else if (!par6 && par8)
298        {
299            par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.1D, (double)par4 + 0.5D, "random.click", 0.4F, 0.5F);
300        }
301        else if (par5 && !par7)
302        {
303            par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.1D, (double)par4 + 0.5D, "random.click", 0.4F, 0.7F);
304        }
305        else if (!par5 && par7)
306        {
307            par1World.playSoundEffect((double)par2 + 0.5D, (double)par3 + 0.1D, (double)par4 + 0.5D, "random.bowhit", 0.4F, 1.2F / (par1World.rand.nextFloat() * 0.2F + 0.9F));
308        }
309    }
310
311    private void notifyNeighborOfChange(World par1World, int par2, int par3, int par4, int par5)
312    {
313        par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID);
314
315        if (par5 == 3)
316        {
317            par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
318        }
319        else if (par5 == 1)
320        {
321            par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
322        }
323        else if (par5 == 0)
324        {
325            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
326        }
327        else if (par5 == 2)
328        {
329            par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
330        }
331    }
332
333    private boolean func_72144_l(World par1World, int par2, int par3, int par4)
334    {
335        if (!this.canPlaceBlockAt(par1World, par2, par3, par4))
336        {
337            this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
338            par1World.func_94571_i(par2, par3, par4);
339            return false;
340        }
341        else
342        {
343            return true;
344        }
345    }
346
347    /**
348     * Updates the blocks bounds based on its current state. Args: world, x, y, z
349     */
350    public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
351    {
352        int l = par1IBlockAccess.getBlockMetadata(par2, par3, par4) & 3;
353        float f = 0.1875F;
354
355        if (l == 3)
356        {
357            this.setBlockBounds(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f);
358        }
359        else if (l == 1)
360        {
361            this.setBlockBounds(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f);
362        }
363        else if (l == 0)
364        {
365            this.setBlockBounds(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F);
366        }
367        else if (l == 2)
368        {
369            this.setBlockBounds(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F);
370        }
371    }
372
373    /**
374     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
375     */
376    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
377    {
378        boolean flag = (par6 & 4) == 4;
379        boolean flag1 = (par6 & 8) == 8;
380
381        if (flag || flag1)
382        {
383            this.func_72143_a(par1World, par2, par3, par4, 0, par6, false, -1, 0);
384        }
385
386        if (flag1)
387        {
388            par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID);
389            int j1 = par6 & 3;
390
391            if (j1 == 3)
392            {
393                par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
394            }
395            else if (j1 == 1)
396            {
397                par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
398            }
399            else if (j1 == 0)
400            {
401                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
402            }
403            else if (j1 == 2)
404            {
405                par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
406            }
407        }
408
409        super.breakBlock(par1World, par2, par3, par4, par5, par6);
410    }
411
412    /**
413     * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube
414     * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X,
415     * Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
416     */
417    public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
418    {
419        return (par1IBlockAccess.getBlockMetadata(par2, par3, par4) & 8) == 8 ? 15 : 0;
420    }
421
422    /**
423     * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z,
424     * side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
425     */
426    public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
427    {
428        int i1 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
429
430        if ((i1 & 8) != 8)
431        {
432            return 0;
433        }
434        else
435        {
436            int j1 = i1 & 3;
437            return j1 == 2 && par5 == 2 ? 15 : (j1 == 0 && par5 == 3 ? 15 : (j1 == 1 && par5 == 4 ? 15 : (j1 == 3 && par5 == 5 ? 15 : 0)));
438        }
439    }
440
441    /**
442     * Can this block provide power. Only wire currently seems to have this change based on its state.
443     */
444    public boolean canProvidePower()
445    {
446        return true;
447    }
448}