    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.entity.Entity;
    009import net.minecraft.entity.player.EntityPlayer;
    010import net.minecraft.entity.player.EnumStatus;
    011import net.minecraft.item.Item;
    012import net.minecraft.util.ChunkCoordinates;
    013import net.minecraft.util.Direction;
    014import net.minecraft.world.IBlockAccess;
    015import net.minecraft.world.World;
    016
    017public 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}