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.func_94571_i(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.func_94571_i(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 public void func_94332_a(IconRegister par1IconRegister) 162 { 163 this.field_94471_cO = new Icon[] {par1IconRegister.func_94245_a("bed_feet_top"), par1IconRegister.func_94245_a("bed_head_top")}; 164 this.field_94472_b = new Icon[] {par1IconRegister.func_94245_a("bed_feet_end"), par1IconRegister.func_94245_a("bed_head_end")}; 165 this.field_94473_c = new Icon[] {par1IconRegister.func_94245_a("bed_feet_side"), par1IconRegister.func_94245_a("bed_head_side")}; 166 } 167 168 /** 169 * The type of render function that is called for this block 170 */ 171 public int getRenderType() 172 { 173 return 14; 174 } 175 176 /** 177 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 178 */ 179 public boolean renderAsNormalBlock() 180 { 181 return false; 182 } 183 184 /** 185 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 186 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 187 */ 188 public boolean isOpaqueCube() 189 { 190 return false; 191 } 192 193 /** 194 * Updates the blocks bounds based on its current state. Args: world, x, y, z 195 */ 196 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4) 197 { 198 this.setBounds(); 199 } 200 201 /** 202 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 203 * their own) Args: x, y, z, neighbor blockID 204 */ 205 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 206 { 207 int i1 = par1World.getBlockMetadata(par2, par3, par4); 208 int j1 = getDirection(i1); 209 210 if (isBlockHeadOfBed(i1)) 211 { 212 if (par1World.getBlockId(par2 - footBlockToHeadBlockMap[j1][0], par3, par4 - footBlockToHeadBlockMap[j1][1]) != this.blockID) 213 { 214 par1World.func_94571_i(par2, par3, par4); 215 } 216 } 217 else if (par1World.getBlockId(par2 + footBlockToHeadBlockMap[j1][0], par3, par4 + footBlockToHeadBlockMap[j1][1]) != this.blockID) 218 { 219 par1World.func_94571_i(par2, par3, par4); 220 221 if (!par1World.isRemote) 222 { 223 this.dropBlockAsItem(par1World, par2, par3, par4, i1, 0); 224 } 225 } 226 } 227 228 /** 229 * Returns the ID of the items to drop on destruction. 230 */ 231 public int idDropped(int par1, Random par2Random, int par3) 232 { 233 return isBlockHeadOfBed(par1) ? 0 : Item.bed.itemID; 234 } 235 236 /** 237 * Set the bounds of the bed block. 238 */ 239 private void setBounds() 240 { 241 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5625F, 1.0F); 242 } 243 244 /** 245 * Returns whether or not this bed block is the head of the bed. 246 */ 247 public static boolean isBlockHeadOfBed(int par0) 248 { 249 return (par0 & 8) != 0; 250 } 251 252 /** 253 * Return whether or not the bed is occupied. 254 */ 255 public static boolean isBedOccupied(int par0) 256 { 257 return (par0 & 4) != 0; 258 } 259 260 /** 261 * Sets whether or not the bed is occupied. 262 */ 263 public static void setBedOccupied(World par0World, int par1, int par2, int par3, boolean par4) 264 { 265 int l = par0World.getBlockMetadata(par1, par2, par3); 266 267 if (par4) 268 { 269 l |= 4; 270 } 271 else 272 { 273 l &= -5; 274 } 275 276 par0World.setBlockMetadataWithNotify(par1, par2, par3, l, 4); 277 } 278 279 /** 280 * Gets the nearest empty chunk coordinates for the player to wake up from a bed into. 281 */ 282 public static ChunkCoordinates getNearestEmptyChunkCoordinates(World par0World, int par1, int par2, int par3, int par4) 283 { 284 int i1 = par0World.getBlockMetadata(par1, par2, par3); 285 int j1 = BlockDirectional.getDirection(i1); 286 287 for (int k1 = 0; k1 <= 1; ++k1) 288 { 289 int l1 = par1 - footBlockToHeadBlockMap[j1][0] * k1 - 1; 290 int i2 = par3 - footBlockToHeadBlockMap[j1][1] * k1 - 1; 291 int j2 = l1 + 2; 292 int k2 = i2 + 2; 293 294 for (int l2 = l1; l2 <= j2; ++l2) 295 { 296 for (int i3 = i2; i3 <= k2; ++i3) 297 { 298 if (par0World.doesBlockHaveSolidTopSurface(l2, par2 - 1, i3) && par0World.isAirBlock(l2, par2, i3) && par0World.isAirBlock(l2, par2 + 1, i3)) 299 { 300 if (par4 <= 0) 301 { 302 return new ChunkCoordinates(l2, par2, i3); 303 } 304 305 --par4; 306 } 307 } 308 } 309 } 310 311 return null; 312 } 313 314 /** 315 * Drops the block items with a specified chance of dropping the specified items 316 */ 317 public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7) 318 { 319 if (!isBlockHeadOfBed(par5)) 320 { 321 super.dropBlockAsItemWithChance(par1World, par2, par3, par4, par5, par6, 0); 322 } 323 } 324 325 /** 326 * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility 327 * and stop pistons 328 */ 329 public int getMobilityFlag() 330 { 331 return 1; 332 } 333 334 @SideOnly(Side.CLIENT) 335 336 /** 337 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) 338 */ 339 public int idPicked(World par1World, int par2, int par3, int par4) 340 { 341 return Item.bed.itemID; 342 } 343 344 /** 345 * Called when the block is attempted to be harvested 346 */ 347 public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) 348 { 349 if (par6EntityPlayer.capabilities.isCreativeMode && isBlockHeadOfBed(par5)) 350 { 351 int i1 = getDirection(par5); 352 par2 -= footBlockToHeadBlockMap[i1][0]; 353 par4 -= footBlockToHeadBlockMap[i1][1]; 354 355 if (par1World.getBlockId(par2, par3, par4) == this.blockID) 356 { 357 par1World.func_94571_i(par2, par3, par4); 358 } 359 } 360 } 361}