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.entity.player.EntityPlayer;
008import net.minecraft.item.Item;
009import net.minecraft.util.AxisAlignedBB;
010import net.minecraft.util.MovingObjectPosition;
011import net.minecraft.util.Vec3;
012import net.minecraft.world.IBlockAccess;
013import net.minecraft.world.World;
014
015public class BlockDoor extends Block
016{
017    protected BlockDoor(int par1, Material par2Material)
018    {
019        super(par1, par2Material);
020        this.blockIndexInTexture = 97;
021
022        if (par2Material == Material.iron)
023        {
024            ++this.blockIndexInTexture;
025        }
026
027        float var3 = 0.5F;
028        float var4 = 1.0F;
029        this.setBlockBounds(0.5F - var3, 0.0F, 0.5F - var3, 0.5F + var3, var4, 0.5F + var3);
030    }
031
032    @SideOnly(Side.CLIENT)
033
034    /**
035     * Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side
036     */
037    public int getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
038    {
039        if (par5 != 0 && par5 != 1)
040        {
041            int var6 = this.getFullMetadata(par1IBlockAccess, par2, par3, par4);
042            int var7 = this.blockIndexInTexture;
043
044            if ((var6 & 8) != 0)
045            {
046                var7 -= 16;
047            }
048
049            int var8 = var6 & 3;
050            boolean var9 = (var6 & 4) != 0;
051
052            if (var9)
053            {
054                if (var8 == 0 && par5 == 2)
055                {
056                    var7 = -var7;
057                }
058                else if (var8 == 1 && par5 == 5)
059                {
060                    var7 = -var7;
061                }
062                else if (var8 == 2 && par5 == 3)
063                {
064                    var7 = -var7;
065                }
066                else if (var8 == 3 && par5 == 4)
067                {
068                    var7 = -var7;
069                }
070            }
071            else
072            {
073                if (var8 == 0 && par5 == 5)
074                {
075                    var7 = -var7;
076                }
077                else if (var8 == 1 && par5 == 3)
078                {
079                    var7 = -var7;
080                }
081                else if (var8 == 2 && par5 == 4)
082                {
083                    var7 = -var7;
084                }
085                else if (var8 == 3 && par5 == 2)
086                {
087                    var7 = -var7;
088                }
089
090                if ((var6 & 16) != 0)
091                {
092                    var7 = -var7;
093                }
094            }
095
096            return var7;
097        }
098        else
099        {
100            return this.blockIndexInTexture;
101        }
102    }
103
104    /**
105     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
106     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
107     */
108    public boolean isOpaqueCube()
109    {
110        return false;
111    }
112
113    public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
114    {
115        int var5 = this.getFullMetadata(par1IBlockAccess, par2, par3, par4);
116        return (var5 & 4) != 0;
117    }
118
119    /**
120     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
121     */
122    public boolean renderAsNormalBlock()
123    {
124        return false;
125    }
126
127    /**
128     * The type of render function that is called for this block
129     */
130    public int getRenderType()
131    {
132        return 7;
133    }
134
135    @SideOnly(Side.CLIENT)
136
137    /**
138     * Returns the bounding box of the wired rectangular prism to render.
139     */
140    public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
141    {
142        this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
143        return super.getSelectedBoundingBoxFromPool(par1World, par2, par3, par4);
144    }
145
146    /**
147     * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
148     * cleared to be reused)
149     */
150    public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
151    {
152        this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
153        return super.getCollisionBoundingBoxFromPool(par1World, par2, par3, par4);
154    }
155
156    /**
157     * Updates the blocks bounds based on its current state. Args: world, x, y, z
158     */
159    public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
160    {
161        this.setDoorRotation(this.getFullMetadata(par1IBlockAccess, par2, par3, par4));
162    }
163
164    /**
165     * Returns 0, 1, 2 or 3 depending on where the hinge is.
166     */
167    public int getDoorOrientation(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
168    {
169        return this.getFullMetadata(par1IBlockAccess, par2, par3, par4) & 3;
170    }
171
172    public boolean isDoorOpen(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
173    {
174        return (this.getFullMetadata(par1IBlockAccess, par2, par3, par4) & 4) != 0;
175    }
176
177    private void setDoorRotation(int par1)
178    {
179        float var2 = 0.1875F;
180        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 2.0F, 1.0F);
181        int var3 = par1 & 3;
182        boolean var4 = (par1 & 4) != 0;
183        boolean var5 = (par1 & 16) != 0;
184
185        if (var3 == 0)
186        {
187            if (var4)
188            {
189                if (!var5)
190                {
191                    this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, var2);
192                }
193                else
194                {
195                    this.setBlockBounds(0.0F, 0.0F, 1.0F - var2, 1.0F, 1.0F, 1.0F);
196                }
197            }
198            else
199            {
200                this.setBlockBounds(0.0F, 0.0F, 0.0F, var2, 1.0F, 1.0F);
201            }
202        }
203        else if (var3 == 1)
204        {
205            if (var4)
206            {
207                if (!var5)
208                {
209                    this.setBlockBounds(1.0F - var2, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
210                }
211                else
212                {
213                    this.setBlockBounds(0.0F, 0.0F, 0.0F, var2, 1.0F, 1.0F);
214                }
215            }
216            else
217            {
218                this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, var2);
219            }
220        }
221        else if (var3 == 2)
222        {
223            if (var4)
224            {
225                if (!var5)
226                {
227                    this.setBlockBounds(0.0F, 0.0F, 1.0F - var2, 1.0F, 1.0F, 1.0F);
228                }
229                else
230                {
231                    this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, var2);
232                }
233            }
234            else
235            {
236                this.setBlockBounds(1.0F - var2, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
237            }
238        }
239        else if (var3 == 3)
240        {
241            if (var4)
242            {
243                if (!var5)
244                {
245                    this.setBlockBounds(0.0F, 0.0F, 0.0F, var2, 1.0F, 1.0F);
246                }
247                else
248                {
249                    this.setBlockBounds(1.0F - var2, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
250                }
251            }
252            else
253            {
254                this.setBlockBounds(0.0F, 0.0F, 1.0F - var2, 1.0F, 1.0F, 1.0F);
255            }
256        }
257    }
258
259    /**
260     * Called when the block is clicked by a player. Args: x, y, z, entityPlayer
261     */
262    public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer) {}
263
264    /**
265     * Called upon block activation (right click on the block.)
266     */
267    public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
268    {
269        if (this.blockMaterial == Material.iron)
270        {
271            return false; //Allow items to interact with the door
272        }
273        else
274        {
275            int var10 = this.getFullMetadata(par1World, par2, par3, par4);
276            int var11 = var10 & 7;
277            var11 ^= 4;
278
279            if ((var10 & 8) == 0)
280            {
281                par1World.setBlockMetadataWithNotify(par2, par3, par4, var11);
282                par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4);
283            }
284            else
285            {
286                par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, var11);
287                par1World.markBlockRangeForRenderUpdate(par2, par3 - 1, par4, par2, par3, par4);
288            }
289
290            par1World.playAuxSFXAtEntity(par5EntityPlayer, 1003, par2, par3, par4, 0);
291            return true;
292        }
293    }
294
295    /**
296     * A function to open a door.
297     */
298    public void onPoweredBlockChange(World par1World, int par2, int par3, int par4, boolean par5)
299    {
300        int var6 = this.getFullMetadata(par1World, par2, par3, par4);
301        boolean var7 = (var6 & 4) != 0;
302
303        if (var7 != par5)
304        {
305            int var8 = var6 & 7;
306            var8 ^= 4;
307
308            if ((var6 & 8) == 0)
309            {
310                par1World.setBlockMetadataWithNotify(par2, par3, par4, var8);
311                par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4);
312            }
313            else
314            {
315                par1World.setBlockMetadataWithNotify(par2, par3 - 1, par4, var8);
316                par1World.markBlockRangeForRenderUpdate(par2, par3 - 1, par4, par2, par3, par4);
317            }
318
319            par1World.playAuxSFXAtEntity((EntityPlayer)null, 1003, par2, par3, par4, 0);
320        }
321    }
322
323    /**
324     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
325     * their own) Args: x, y, z, neighbor blockID
326     */
327    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
328    {
329        int var6 = par1World.getBlockMetadata(par2, par3, par4);
330
331        if ((var6 & 8) == 0)
332        {
333            boolean var7 = false;
334
335            if (par1World.getBlockId(par2, par3 + 1, par4) != this.blockID)
336            {
337                par1World.setBlockWithNotify(par2, par3, par4, 0);
338                var7 = true;
339            }
340
341            if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4))
342            {
343                par1World.setBlockWithNotify(par2, par3, par4, 0);
344                var7 = true;
345
346                if (par1World.getBlockId(par2, par3 + 1, par4) == this.blockID)
347                {
348                    par1World.setBlockWithNotify(par2, par3 + 1, par4, 0);
349                }
350            }
351
352            if (var7)
353            {
354                if (!par1World.isRemote)
355                {
356                    this.dropBlockAsItem(par1World, par2, par3, par4, var6, 0);
357                }
358            }
359            else
360            {
361                boolean var8 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4);
362
363                if ((var8 || par5 > 0 && Block.blocksList[par5].canProvidePower()) && par5 != this.blockID)
364                {
365                    this.onPoweredBlockChange(par1World, par2, par3, par4, var8);
366                }
367            }
368        }
369        else
370        {
371            if (par1World.getBlockId(par2, par3 - 1, par4) != this.blockID)
372            {
373                par1World.setBlockWithNotify(par2, par3, par4, 0);
374            }
375
376            if (par5 > 0 && par5 != this.blockID)
377            {
378                this.onNeighborBlockChange(par1World, par2, par3 - 1, par4, par5);
379            }
380        }
381    }
382
383    /**
384     * Returns the ID of the items to drop on destruction.
385     */
386    public int idDropped(int par1, Random par2Random, int par3)
387    {
388        return (par1 & 8) != 0 ? 0 : (this.blockMaterial == Material.iron ? Item.doorSteel.itemID : Item.doorWood.itemID);
389    }
390
391    /**
392     * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world,
393     * x, y, z, startVec, endVec
394     */
395    public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3)
396    {
397        this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
398        return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3);
399    }
400
401    /**
402     * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
403     */
404    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
405    {
406        return par3 >= 255 ? false : par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) && super.canPlaceBlockAt(par1World, par2, par3, par4) && super.canPlaceBlockAt(par1World, par2, par3 + 1, par4);
407    }
408
409    /**
410     * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
411     * and stop pistons
412     */
413    public int getMobilityFlag()
414    {
415        return 1;
416    }
417
418    /**
419     * Returns the full metadata value created by combining the metadata of both blocks the door takes up.
420     */
421    public int getFullMetadata(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
422    {
423        int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
424        boolean var6 = (var5 & 8) != 0;
425        int var7;
426        int var8;
427
428        if (var6)
429        {
430            var7 = par1IBlockAccess.getBlockMetadata(par2, par3 - 1, par4);
431            var8 = var5;
432        }
433        else
434        {
435            var7 = var5;
436            var8 = par1IBlockAccess.getBlockMetadata(par2, par3 + 1, par4);
437        }
438
439        boolean var9 = (var8 & 1) != 0;
440        return var7 & 7 | (var6 ? 8 : 0) | (var9 ? 16 : 0);
441    }
442
443    @SideOnly(Side.CLIENT)
444
445    /**
446     * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
447     */
448    public int idPicked(World par1World, int par2, int par3, int par4)
449    {
450        return this.blockMaterial == Material.iron ? Item.doorSteel.itemID : Item.doorWood.itemID;
451    }
452
453    /**
454     * Called when the block is attempted to be harvested
455     */
456    public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
457    {
458        if (par6EntityPlayer.capabilities.isCreativeMode && (par5 & 8) != 0 && par1World.getBlockId(par2, par3 - 1, par4) == this.blockID)
459        {
460            par1World.setBlockWithNotify(par2, par3 - 1, par4, 0);
461        }
462    }
463}