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