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.entity.player.EntityPlayer;
008    import net.minecraft.item.Item;
009    import net.minecraft.util.AxisAlignedBB;
010    import net.minecraft.util.MovingObjectPosition;
011    import net.minecraft.util.Vec3;
012    import net.minecraft.world.IBlockAccess;
013    import net.minecraft.world.World;
014    
015    public 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    }