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 }