001 package net.minecraft.src;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.SideOnly;
005 import java.util.Iterator;
006 import java.util.Random;
007
008 public class BlockBed extends BlockDirectional
009 {
010 /** Maps the foot-of-bed block to the head-of-bed block. */
011 public static final int[][] footBlockToHeadBlockMap = new int[][] {{0, 1}, { -1, 0}, {0, -1}, {1, 0}};
012
013 public BlockBed(int par1)
014 {
015 super(par1, 134, Material.cloth);
016 this.setBounds();
017 }
018
019 /**
020 * Called upon block activation (right click on the block.)
021 */
022 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
023 {
024 if (par1World.isRemote)
025 {
026 return true;
027 }
028 else
029 {
030 int var10 = par1World.getBlockMetadata(par2, par3, par4);
031
032 if (!isBlockHeadOfBed(var10))
033 {
034 int var11 = getDirection(var10);
035 par2 += footBlockToHeadBlockMap[var11][0];
036 par4 += footBlockToHeadBlockMap[var11][1];
037
038 if (par1World.getBlockId(par2, par3, par4) != this.blockID)
039 {
040 return true;
041 }
042
043 var10 = par1World.getBlockMetadata(par2, par3, par4);
044 }
045
046 if (!par1World.provider.canRespawnHere())
047 {
048 double var19 = (double)par2 + 0.5D;
049 double var21 = (double)par3 + 0.5D;
050 double var15 = (double)par4 + 0.5D;
051 par1World.setBlockWithNotify(par2, par3, par4, 0);
052 int var17 = getDirection(var10);
053 par2 += footBlockToHeadBlockMap[var17][0];
054 par4 += footBlockToHeadBlockMap[var17][1];
055
056 if (par1World.getBlockId(par2, par3, par4) == this.blockID)
057 {
058 par1World.setBlockWithNotify(par2, par3, par4, 0);
059 var19 = (var19 + (double)par2 + 0.5D) / 2.0D;
060 var21 = (var21 + (double)par3 + 0.5D) / 2.0D;
061 var15 = (var15 + (double)par4 + 0.5D) / 2.0D;
062 }
063
064 par1World.newExplosion((Entity)null, (double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F), 5.0F, true, true);
065 return true;
066 }
067 else
068 {
069 if (isBedOccupied(var10))
070 {
071 EntityPlayer var18 = null;
072 Iterator var12 = par1World.playerEntities.iterator();
073
074 while (var12.hasNext())
075 {
076 EntityPlayer var13 = (EntityPlayer)var12.next();
077
078 if (var13.isPlayerSleeping())
079 {
080 ChunkCoordinates var14 = var13.playerLocation;
081
082 if (var14.posX == par2 && var14.posY == par3 && var14.posZ == par4)
083 {
084 var18 = var13;
085 }
086 }
087 }
088
089 if (var18 != null)
090 {
091 par5EntityPlayer.addChatMessage("tile.bed.occupied");
092 return true;
093 }
094
095 setBedOccupied(par1World, par2, par3, par4, false);
096 }
097
098 EnumStatus var20 = par5EntityPlayer.sleepInBedAt(par2, par3, par4);
099
100 if (var20 == EnumStatus.OK)
101 {
102 setBedOccupied(par1World, par2, par3, par4, true);
103 return true;
104 }
105 else
106 {
107 if (var20 == EnumStatus.NOT_POSSIBLE_NOW)
108 {
109 par5EntityPlayer.addChatMessage("tile.bed.noSleep");
110 }
111 else if (var20 == EnumStatus.NOT_SAFE)
112 {
113 par5EntityPlayer.addChatMessage("tile.bed.notSafe");
114 }
115
116 return true;
117 }
118 }
119 }
120 }
121
122 /**
123 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
124 */
125 public int getBlockTextureFromSideAndMetadata(int par1, int par2)
126 {
127 if (par1 == 0)
128 {
129 return Block.planks.blockIndexInTexture;
130 }
131 else
132 {
133 int var3 = getDirection(par2);
134 int var4 = Direction.bedDirection[var3][par1];
135 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));
136 }
137 }
138
139 /**
140 * The type of render function that is called for this block
141 */
142 public int getRenderType()
143 {
144 return 14;
145 }
146
147 /**
148 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
149 */
150 public boolean renderAsNormalBlock()
151 {
152 return false;
153 }
154
155 /**
156 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
157 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
158 */
159 public boolean isOpaqueCube()
160 {
161 return false;
162 }
163
164 /**
165 * Updates the blocks bounds based on its current state. Args: world, x, y, z
166 */
167 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
168 {
169 this.setBounds();
170 }
171
172 /**
173 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
174 * their own) Args: x, y, z, neighbor blockID
175 */
176 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
177 {
178 int var6 = par1World.getBlockMetadata(par2, par3, par4);
179 int var7 = getDirection(var6);
180
181 if (isBlockHeadOfBed(var6))
182 {
183 if (par1World.getBlockId(par2 - footBlockToHeadBlockMap[var7][0], par3, par4 - footBlockToHeadBlockMap[var7][1]) != this.blockID)
184 {
185 par1World.setBlockWithNotify(par2, par3, par4, 0);
186 }
187 }
188 else if (par1World.getBlockId(par2 + footBlockToHeadBlockMap[var7][0], par3, par4 + footBlockToHeadBlockMap[var7][1]) != this.blockID)
189 {
190 par1World.setBlockWithNotify(par2, par3, par4, 0);
191
192 if (!par1World.isRemote)
193 {
194 this.dropBlockAsItem(par1World, par2, par3, par4, var6, 0);
195 }
196 }
197 }
198
199 /**
200 * Returns the ID of the items to drop on destruction.
201 */
202 public int idDropped(int par1, Random par2Random, int par3)
203 {
204 return isBlockHeadOfBed(par1) ? 0 : Item.bed.shiftedIndex;
205 }
206
207 /**
208 * Set the bounds of the bed block.
209 */
210 private void setBounds()
211 {
212 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5625F, 1.0F);
213 }
214
215 /**
216 * Returns whether or not this bed block is the head of the bed.
217 */
218 public static boolean isBlockHeadOfBed(int par0)
219 {
220 return (par0 & 8) != 0;
221 }
222
223 /**
224 * Return whether or not the bed is occupied.
225 */
226 public static boolean isBedOccupied(int par0)
227 {
228 return (par0 & 4) != 0;
229 }
230
231 /**
232 * Sets whether or not the bed is occupied.
233 */
234 public static void setBedOccupied(World par0World, int par1, int par2, int par3, boolean par4)
235 {
236 int var5 = par0World.getBlockMetadata(par1, par2, par3);
237
238 if (par4)
239 {
240 var5 |= 4;
241 }
242 else
243 {
244 var5 &= -5;
245 }
246
247 par0World.setBlockMetadataWithNotify(par1, par2, par3, var5);
248 }
249
250 /**
251 * Gets the nearest empty chunk coordinates for the player to wake up from a bed into.
252 */
253 public static ChunkCoordinates getNearestEmptyChunkCoordinates(World par0World, int par1, int par2, int par3, int par4)
254 {
255 int var5 = par0World.getBlockMetadata(par1, par2, par3);
256 int var6 = BlockDirectional.getDirection(var5);
257
258 for (int var7 = 0; var7 <= 1; ++var7)
259 {
260 int var8 = par1 - footBlockToHeadBlockMap[var6][0] * var7 - 1;
261 int var9 = par3 - footBlockToHeadBlockMap[var6][1] * var7 - 1;
262 int var10 = var8 + 2;
263 int var11 = var9 + 2;
264
265 for (int var12 = var8; var12 <= var10; ++var12)
266 {
267 for (int var13 = var9; var13 <= var11; ++var13)
268 {
269 if (par0World.doesBlockHaveSolidTopSurface(var12, par2 - 1, var13) && par0World.isAirBlock(var12, par2, var13) && par0World.isAirBlock(var12, par2 + 1, var13))
270 {
271 if (par4 <= 0)
272 {
273 return new ChunkCoordinates(var12, par2, var13);
274 }
275
276 --par4;
277 }
278 }
279 }
280 }
281
282 return null;
283 }
284
285 /**
286 * Drops the block items with a specified chance of dropping the specified items
287 */
288 public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7)
289 {
290 if (!isBlockHeadOfBed(par5))
291 {
292 super.dropBlockAsItemWithChance(par1World, par2, par3, par4, par5, par6, 0);
293 }
294 }
295
296 /**
297 * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
298 * and stop pistons
299 */
300 public int getMobilityFlag()
301 {
302 return 1;
303 }
304
305 @SideOnly(Side.CLIENT)
306
307 /**
308 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
309 */
310 public int idPicked(World par1World, int par2, int par3, int par4)
311 {
312 return Item.bed.shiftedIndex;
313 }
314
315 /**
316 * Called when the block is attempted to be harvested
317 */
318 public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
319 {
320 if (par6EntityPlayer.capabilities.isCreativeMode && isBlockHeadOfBed(par5))
321 {
322 int var7 = getDirection(par5);
323 par2 -= footBlockToHeadBlockMap[var7][0];
324 par4 -= footBlockToHeadBlockMap[var7][1];
325
326 if (par1World.getBlockId(par2, par3, par4) == this.blockID)
327 {
328 par1World.setBlockWithNotify(par2, par3, par4, 0);
329 }
330 }
331 }
332 }