    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[] bedSideIcons;
    028    @SideOnly(Side.CLIENT)
    029    private Icon[] bedTopIcons;
    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 getIcon(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.bedTopIcons[i1] : this.bedSideIcons[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.bedTopIcons = 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.bedSideIcons = 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}