001    package net.minecraft.block;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.SideOnly;
005    import java.util.Iterator;
006    import java.util.Random;
007    import net.minecraft.block.material.Material;
008    import net.minecraft.entity.Entity;
009    import net.minecraft.entity.player.EntityPlayer;
010    import net.minecraft.entity.player.EnumStatus;
011    import net.minecraft.item.Item;
012    import net.minecraft.util.ChunkCoordinates;
013    import net.minecraft.util.Direction;
014    import net.minecraft.world.IBlockAccess;
015    import net.minecraft.world.World;
016    
017    public class BlockBed extends BlockDirectional
018    {
019        /** Maps the foot-of-bed block to the head-of-bed block. */
020        public static final int[][] footBlockToHeadBlockMap = new int[][] {{0, 1}, { -1, 0}, {0, -1}, {1, 0}};
021    
022        public BlockBed(int par1)
023        {
024            super(par1, 134, Material.cloth);
025            this.setBounds();
026        }
027    
028        /**
029         * Called upon block activation (right click on the block.)
030         */
031        public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
032        {
033            if (par1World.isRemote)
034            {
035                return true;
036            }
037            else
038            {
039                int var10 = par1World.getBlockMetadata(par2, par3, par4);
040    
041                if (!isBlockHeadOfBed(var10))
042                {
043                    int var11 = getDirection(var10);
044                    par2 += footBlockToHeadBlockMap[var11][0];
045                    par4 += footBlockToHeadBlockMap[var11][1];
046    
047                    if (par1World.getBlockId(par2, par3, par4) != this.blockID)
048                    {
049                        return true;
050                    }
051    
052                    var10 = par1World.getBlockMetadata(par2, par3, par4);
053                }
054    
055                if (!par1World.provider.canRespawnHere())
056                {
057                    double var19 = (double)par2 + 0.5D;
058                    double var21 = (double)par3 + 0.5D;
059                    double var15 = (double)par4 + 0.5D;
060                    par1World.setBlockWithNotify(par2, par3, par4, 0);
061                    int var17 = getDirection(var10);
062                    par2 += footBlockToHeadBlockMap[var17][0];
063                    par4 += footBlockToHeadBlockMap[var17][1];
064    
065                    if (par1World.getBlockId(par2, par3, par4) == this.blockID)
066                    {
067                        par1World.setBlockWithNotify(par2, par3, par4, 0);
068                        var19 = (var19 + (double)par2 + 0.5D) / 2.0D;
069                        var21 = (var21 + (double)par3 + 0.5D) / 2.0D;
070                        var15 = (var15 + (double)par4 + 0.5D) / 2.0D;
071                    }
072    
073                    par1World.newExplosion((Entity)null, (double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F), 5.0F, true, true);
074                    return true;
075                }
076                else
077                {
078                    if (isBedOccupied(var10))
079                    {
080                        EntityPlayer var18 = null;
081                        Iterator var12 = par1World.playerEntities.iterator();
082    
083                        while (var12.hasNext())
084                        {
085                            EntityPlayer var13 = (EntityPlayer)var12.next();
086    
087                            if (var13.isPlayerSleeping())
088                            {
089                                ChunkCoordinates var14 = var13.playerLocation;
090    
091                                if (var14.posX == par2 && var14.posY == par3 && var14.posZ == par4)
092                                {
093                                    var18 = var13;
094                                }
095                            }
096                        }
097    
098                        if (var18 != null)
099                        {
100                            par5EntityPlayer.addChatMessage("tile.bed.occupied");
101                            return true;
102                        }
103    
104                        setBedOccupied(par1World, par2, par3, par4, false);
105                    }
106    
107                    EnumStatus var20 = par5EntityPlayer.sleepInBedAt(par2, par3, par4);
108    
109                    if (var20 == EnumStatus.OK)
110                    {
111                        setBedOccupied(par1World, par2, par3, par4, true);
112                        return true;
113                    }
114                    else
115                    {
116                        if (var20 == EnumStatus.NOT_POSSIBLE_NOW)
117                        {
118                            par5EntityPlayer.addChatMessage("tile.bed.noSleep");
119                        }
120                        else if (var20 == EnumStatus.NOT_SAFE)
121                        {
122                            par5EntityPlayer.addChatMessage("tile.bed.notSafe");
123                        }
124    
125                        return true;
126                    }
127                }
128            }
129        }
130    
131        /**
132         * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
133         */
134        public int getBlockTextureFromSideAndMetadata(int par1, int par2)
135        {
136            if (par1 == 0)
137            {
138                return Block.planks.blockIndexInTexture;
139            }
140            else
141            {
142                int var3 = getDirection(par2);
143                int var4 = Direction.bedDirection[var3][par1];
144                return isBlockHeadOfBed(par2) ? (var4 == 2 ? this.blockIndexInTexture + 2 + 16 : (var4 != 5 && var4 != 4 ? this.blockIndexInTexture + 1 : this.blockIndexInTexture + 1 + 16)) : (var4 == 3 ? this.blockIndexInTexture - 1 + 16 : (var4 != 5 && var4 != 4 ? this.blockIndexInTexture : this.blockIndexInTexture + 16));
145            }
146        }
147    
148        /**
149         * The type of render function that is called for this block
150         */
151        public int getRenderType()
152        {
153            return 14;
154        }
155    
156        /**
157         * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
158         */
159        public boolean renderAsNormalBlock()
160        {
161            return false;
162        }
163    
164        /**
165         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
166         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
167         */
168        public boolean isOpaqueCube()
169        {
170            return false;
171        }
172    
173        /**
174         * Updates the blocks bounds based on its current state. Args: world, x, y, z
175         */
176        public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
177        {
178            this.setBounds();
179        }
180    
181        /**
182         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
183         * their own) Args: x, y, z, neighbor blockID
184         */
185        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
186        {
187            int var6 = par1World.getBlockMetadata(par2, par3, par4);
188            int var7 = getDirection(var6);
189    
190            if (isBlockHeadOfBed(var6))
191            {
192                if (par1World.getBlockId(par2 - footBlockToHeadBlockMap[var7][0], par3, par4 - footBlockToHeadBlockMap[var7][1]) != this.blockID)
193                {
194                    par1World.setBlockWithNotify(par2, par3, par4, 0);
195                }
196            }
197            else if (par1World.getBlockId(par2 + footBlockToHeadBlockMap[var7][0], par3, par4 + footBlockToHeadBlockMap[var7][1]) != this.blockID)
198            {
199                par1World.setBlockWithNotify(par2, par3, par4, 0);
200    
201                if (!par1World.isRemote)
202                {
203                    this.dropBlockAsItem(par1World, par2, par3, par4, var6, 0);
204                }
205            }
206        }
207    
208        /**
209         * Returns the ID of the items to drop on destruction.
210         */
211        public int idDropped(int par1, Random par2Random, int par3)
212        {
213            return isBlockHeadOfBed(par1) ? 0 : Item.bed.itemID;
214        }
215    
216        /**
217         * Set the bounds of the bed block.
218         */
219        private void setBounds()
220        {
221            this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5625F, 1.0F);
222        }
223    
224        /**
225         * Returns whether or not this bed block is the head of the bed.
226         */
227        public static boolean isBlockHeadOfBed(int par0)
228        {
229            return (par0 & 8) != 0;
230        }
231    
232        /**
233         * Return whether or not the bed is occupied.
234         */
235        public static boolean isBedOccupied(int par0)
236        {
237            return (par0 & 4) != 0;
238        }
239    
240        /**
241         * Sets whether or not the bed is occupied.
242         */
243        public static void setBedOccupied(World par0World, int par1, int par2, int par3, boolean par4)
244        {
245            int var5 = par0World.getBlockMetadata(par1, par2, par3);
246    
247            if (par4)
248            {
249                var5 |= 4;
250            }
251            else
252            {
253                var5 &= -5;
254            }
255    
256            par0World.setBlockMetadataWithNotify(par1, par2, par3, var5);
257        }
258    
259        /**
260         * Gets the nearest empty chunk coordinates for the player to wake up from a bed into.
261         */
262        public static ChunkCoordinates getNearestEmptyChunkCoordinates(World par0World, int par1, int par2, int par3, int par4)
263        {
264            int var5 = par0World.getBlockMetadata(par1, par2, par3);
265            int var6 = BlockDirectional.getDirection(var5);
266    
267            for (int var7 = 0; var7 <= 1; ++var7)
268            {
269                int var8 = par1 - footBlockToHeadBlockMap[var6][0] * var7 - 1;
270                int var9 = par3 - footBlockToHeadBlockMap[var6][1] * var7 - 1;
271                int var10 = var8 + 2;
272                int var11 = var9 + 2;
273    
274                for (int var12 = var8; var12 <= var10; ++var12)
275                {
276                    for (int var13 = var9; var13 <= var11; ++var13)
277                    {
278                        if (par0World.doesBlockHaveSolidTopSurface(var12, par2 - 1, var13) && par0World.isAirBlock(var12, par2, var13) && par0World.isAirBlock(var12, par2 + 1, var13))
279                        {
280                            if (par4 <= 0)
281                            {
282                                return new ChunkCoordinates(var12, par2, var13);
283                            }
284    
285                            --par4;
286                        }
287                    }
288                }
289            }
290    
291            return null;
292        }
293    
294        /**
295         * Drops the block items with a specified chance of dropping the specified items
296         */
297        public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7)
298        {
299            if (!isBlockHeadOfBed(par5))
300            {
301                super.dropBlockAsItemWithChance(par1World, par2, par3, par4, par5, par6, 0);
302            }
303        }
304    
305        /**
306         * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
307         * and stop pistons
308         */
309        public int getMobilityFlag()
310        {
311            return 1;
312        }
313    
314        @SideOnly(Side.CLIENT)
315    
316        /**
317         * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
318         */
319        public int idPicked(World par1World, int par2, int par3, int par4)
320        {
321            return Item.bed.itemID;
322        }
323    
324        /**
325         * Called when the block is attempted to be harvested
326         */
327        public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
328        {
329            if (par6EntityPlayer.capabilities.isCreativeMode && isBlockHeadOfBed(par5))
330            {
331                int var7 = getDirection(par5);
332                par2 -= footBlockToHeadBlockMap[var7][0];
333                par4 -= footBlockToHeadBlockMap[var7][1];
334    
335                if (par1World.getBlockId(par2, par3, par4) == this.blockID)
336                {
337                    par1World.setBlockWithNotify(par2, par3, par4, 0);
338                }
339            }
340        }
341    }