001 package net.minecraft.block; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import java.util.Iterator; 006 import java.util.Random; 007 import net.minecraft.block.material.Material; 008 import net.minecraft.entity.Entity; 009 import net.minecraft.entity.player.EntityPlayer; 010 import net.minecraft.entity.player.EnumStatus; 011 import net.minecraft.item.Item; 012 import net.minecraft.util.ChunkCoordinates; 013 import net.minecraft.util.Direction; 014 import net.minecraft.world.IBlockAccess; 015 import net.minecraft.world.World; 016 017 public 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 }