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