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}