001 package net.minecraft.src;
002
003 import java.util.Random;
004
005 import net.minecraftforge.common.ForgeDirection;
006 import static net.minecraftforge.common.ForgeDirection.*;
007
008 public class BlockRail extends Block
009 {
010 /** Power related rails have this field at true. */
011 private final boolean isPowered;
012
013 /**
014 * Forge: Moved render type to a field and a setter.
015 * This allows for a mod to change the render type
016 * for vanilla rails, and any mod rails that extend
017 * this class.
018 */
019 private int renderType = 9;
020
021 public void setRenderType(int value)
022 {
023 renderType = value;
024 }
025
026 /**
027 * Returns true if the block at the coordinates of world passed is a valid rail block (current is rail, powered or
028 * detector).
029 */
030 public static final boolean isRailBlockAt(World par0World, int par1, int par2, int par3)
031 {
032 int var4 = par0World.getBlockId(par1, par2, par3);
033 return isRailBlock(var4);
034 }
035
036 /**
037 * Return true if the parameter is a blockID for a valid rail block (current is rail, powered or detector).
038 */
039 public static final boolean isRailBlock(int par0)
040 {
041 return Block.blocksList[par0] instanceof BlockRail;
042 }
043
044 protected BlockRail(int par1, int par2, boolean par3)
045 {
046 super(par1, par2, Material.circuits);
047 this.isPowered = par3;
048 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
049 this.setCreativeTab(CreativeTabs.tabTransport);
050 }
051
052 /**
053 * Returns true if the block is power related rail.
054 */
055 public boolean isPowered()
056 {
057 return this.isPowered;
058 }
059
060 /**
061 * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
062 * cleared to be reused)
063 */
064 public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
065 {
066 return null;
067 }
068
069 /**
070 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
071 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
072 */
073 public boolean isOpaqueCube()
074 {
075 return false;
076 }
077
078 /**
079 * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world,
080 * x, y, z, startVec, endVec
081 */
082 public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3)
083 {
084 this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
085 return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3);
086 }
087
088 /**
089 * Updates the blocks bounds based on its current state. Args: world, x, y, z
090 */
091 public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
092 {
093 int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
094
095 if (var5 >= 2 && var5 <= 5)
096 {
097 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F);
098 }
099 else
100 {
101 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
102 }
103 }
104
105 /**
106 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
107 */
108 public int getBlockTextureFromSideAndMetadata(int par1, int par2)
109 {
110 if (this.isPowered)
111 {
112 if (this.blockID == Block.railPowered.blockID && (par2 & 8) == 0)
113 {
114 return this.blockIndexInTexture - 16;
115 }
116 }
117 else if (par2 >= 6)
118 {
119 return this.blockIndexInTexture - 16;
120 }
121
122 return this.blockIndexInTexture;
123 }
124
125 /**
126 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
127 */
128 public boolean renderAsNormalBlock()
129 {
130 return false;
131 }
132
133 /**
134 * The type of render function that is called for this block
135 */
136 public int getRenderType()
137 {
138 return renderType;
139 }
140
141 /**
142 * Returns the quantity of items to drop on block destruction.
143 */
144 public int quantityDropped(Random par1Random)
145 {
146 return 1;
147 }
148
149 /**
150 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
151 */
152 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
153 {
154 return par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP);
155 }
156
157 /**
158 * Called whenever the block is added into the world. Args: world, x, y, z
159 */
160 public void onBlockAdded(World par1World, int par2, int par3, int par4)
161 {
162 if (!par1World.isRemote)
163 {
164 this.refreshTrackShape(par1World, par2, par3, par4, true);
165
166 if (this.blockID == Block.railPowered.blockID)
167 {
168 this.onNeighborBlockChange(par1World, par2, par3, par4, this.blockID);
169 }
170 }
171 }
172
173 /**
174 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
175 * their own) Args: x, y, z, neighbor blockID
176 */
177 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
178 {
179 if (!par1World.isRemote)
180 {
181 int var6 = par1World.getBlockMetadata(par2, par3, par4);
182 int var7 = var6;
183
184 if (this.isPowered)
185 {
186 var7 = var6 & 7;
187 }
188
189 boolean var8 = false;
190
191 if (!par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP))
192 {
193 var8 = true;
194 }
195
196 if (var7 == 2 && !par1World.isBlockSolidOnSide(par2 + 1, par3, par4, UP))
197 {
198 var8 = true;
199 }
200
201 if (var7 == 3 && !par1World.isBlockSolidOnSide(par2 - 1, par3, par4, UP))
202 {
203 var8 = true;
204 }
205
206 if (var7 == 4 && !par1World.isBlockSolidOnSide(par2, par3, par4 - 1, UP))
207 {
208 var8 = true;
209 }
210
211 if (var7 == 5 && !par1World.isBlockSolidOnSide(par2, par3, par4 + 1, UP))
212 {
213 var8 = true;
214 }
215
216 if (var8)
217 {
218 this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
219 par1World.setBlockWithNotify(par2, par3, par4, 0);
220 }
221 else if (this.blockID == Block.railPowered.blockID)
222 {
223 boolean var9 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4);
224 var9 = var9 || this.isNeighborRailPowered(par1World, par2, par3, par4, var6, true, 0) || this.isNeighborRailPowered(par1World, par2, par3, par4, var6, false, 0);
225 boolean var10 = false;
226
227 if (var9 && (var6 & 8) == 0)
228 {
229 par1World.setBlockMetadataWithNotify(par2, par3, par4, var7 | 8);
230 var10 = true;
231 }
232 else if (!var9 && (var6 & 8) != 0)
233 {
234 par1World.setBlockMetadataWithNotify(par2, par3, par4, var7);
235 var10 = true;
236 }
237
238 if (var10)
239 {
240 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
241
242 if (var7 == 2 || var7 == 3 || var7 == 4 || var7 == 5)
243 {
244 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
245 }
246 }
247 }
248 else if (par5 > 0 && Block.blocksList[par5].canProvidePower() && !this.isPowered && RailLogic.getAdjacentTracks(new RailLogic(this, par1World, par2, par3, par4)) == 3)
249 {
250 this.refreshTrackShape(par1World, par2, par3, par4, false);
251 }
252 }
253 }
254
255 /**
256 * Completely recalculates the track shape based on neighboring tracks
257 */
258 private void refreshTrackShape(World par1World, int par2, int par3, int par4, boolean par5)
259 {
260 if (!par1World.isRemote)
261 {
262 (new RailLogic(this, par1World, par2, par3, par4)).refreshTrackShape(par1World.isBlockIndirectlyGettingPowered(par2, par3, par4), par5);
263 }
264 }
265
266 /**
267 * Powered minecart rail is conductive like wire, so check for powered neighbors
268 */
269 private boolean isNeighborRailPowered(World par1World, int par2, int par3, int par4, int par5, boolean par6, int par7)
270 {
271 if (par7 >= 8)
272 {
273 return false;
274 }
275 else
276 {
277 int var8 = par5 & 7;
278 boolean var9 = true;
279
280 switch (var8)
281 {
282 case 0:
283 if (par6)
284 {
285 ++par4;
286 }
287 else
288 {
289 --par4;
290 }
291
292 break;
293 case 1:
294 if (par6)
295 {
296 --par2;
297 }
298 else
299 {
300 ++par2;
301 }
302
303 break;
304 case 2:
305 if (par6)
306 {
307 --par2;
308 }
309 else
310 {
311 ++par2;
312 ++par3;
313 var9 = false;
314 }
315
316 var8 = 1;
317 break;
318 case 3:
319 if (par6)
320 {
321 --par2;
322 ++par3;
323 var9 = false;
324 }
325 else
326 {
327 ++par2;
328 }
329
330 var8 = 1;
331 break;
332 case 4:
333 if (par6)
334 {
335 ++par4;
336 }
337 else
338 {
339 --par4;
340 ++par3;
341 var9 = false;
342 }
343
344 var8 = 0;
345 break;
346 case 5:
347 if (par6)
348 {
349 ++par4;
350 ++par3;
351 var9 = false;
352 }
353 else
354 {
355 --par4;
356 }
357
358 var8 = 0;
359 }
360
361 return this.isRailPassingPower(par1World, par2, par3, par4, par6, par7, var8) ? true : var9 && this.isRailPassingPower(par1World, par2, par3 - 1, par4, par6, par7, var8);
362 }
363 }
364
365 /**
366 * Returns true if the specified rail is passing power to its neighbor
367 */
368 private boolean isRailPassingPower(World par1World, int par2, int par3, int par4, boolean par5, int par6, int par7)
369 {
370 int var8 = par1World.getBlockId(par2, par3, par4);
371
372 if (var8 == Block.railPowered.blockID)
373 {
374 int var9 = par1World.getBlockMetadata(par2, par3, par4);
375 int var10 = var9 & 7;
376
377 if (par7 == 1 && (var10 == 0 || var10 == 4 || var10 == 5))
378 {
379 return false;
380 }
381
382 if (par7 == 0 && (var10 == 1 || var10 == 2 || var10 == 3))
383 {
384 return false;
385 }
386
387 if ((var9 & 8) != 0)
388 {
389 if (par1World.isBlockIndirectlyGettingPowered(par2, par3, par4))
390 {
391 return true;
392 }
393
394 return this.isNeighborRailPowered(par1World, par2, par3, par4, var9, par5, par6 + 1);
395 }
396 }
397
398 return false;
399 }
400
401 /**
402 * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
403 * and stop pistons
404 */
405 public int getMobilityFlag()
406 {
407 return 0;
408 }
409
410 /**
411 * Return true if the blocks passed is a power related rail.
412 * @deprecated
413 * This function is no longer called by Minecraft
414 */
415 @Deprecated
416 static boolean isPoweredBlockRail(BlockRail par0BlockRail)
417 {
418 return par0BlockRail.isPowered;
419 }
420
421 /**
422 * Return true if the rail can make corners.
423 * Used by placement logic.
424 * @param world The world.
425 * @param x The rail X coordinate.
426 * @param y The rail Y coordinate.
427 * @param z The rail Z coordinate.
428 * @return True if the rail can make corners.
429 */
430 public boolean isFlexibleRail(World world, int y, int x, int z)
431 {
432 return !isPowered;
433 }
434
435 /**
436 * Returns true if the rail can make up and down slopes.
437 * Used by placement logic.
438 * @param world The world.
439 * @param x The rail X coordinate.
440 * @param y The rail Y coordinate.
441 * @param z The rail Z coordinate.
442 * @return True if the rail can make slopes.
443 */
444 public boolean canMakeSlopes(World world, int x, int y, int z)
445 {
446 return true;
447 }
448
449 /**
450 * Return the rails metadata (without the power bit if the rail uses one).
451 * Can be used to make the cart think the rail something other than it is,
452 * for example when making diamond junctions or switches.
453 * The cart parameter will often be null unless it it called from EntityMinecart.
454 *
455 * Valid rail metadata is defined as follows:
456 * 0x0: flat track going North-South
457 * 0x1: flat track going West-East
458 * 0x2: track ascending to the East
459 * 0x3: track ascending to the West
460 * 0x4: track ascending to the North
461 * 0x5: track ascending to the South
462 * 0x6: WestNorth corner (connecting East and South)
463 * 0x7: EastNorth corner (connecting West and South)
464 * 0x8: EastSouth corner (connecting West and North)
465 * 0x9: WestSouth corner (connecting East and North)
466 *
467 * All directions are Notch defined.
468 * In MC Beta 1.8.3 the Sun rises in the North.
469 * In MC 1.0.0 the Sun rises in the East.
470 *
471 * @param world The world.
472 * @param cart The cart asking for the metadata, null if it is not called by EntityMinecart.
473 * @param y The rail X coordinate.
474 * @param x The rail Y coordinate.
475 * @param z The rail Z coordinate.
476 * @return The metadata.
477 */
478 public int getBasicRailMetadata(IBlockAccess world, EntityMinecart cart, int x, int y, int z)
479 {
480 int meta = world.getBlockMetadata(x, y, z);
481 if(isPowered)
482 {
483 meta = meta & 7;
484 }
485 return meta;
486 }
487
488 /**
489 * Returns the max speed of the rail at the specified position.
490 * @param world The world.
491 * @param cart The cart on the rail, may be null.
492 * @param x The rail X coordinate.
493 * @param y The rail Y coordinate.
494 * @param z The rail Z coordinate.
495 * @return The max speed of the current rail.
496 */
497 public float getRailMaxSpeed(World world, EntityMinecart cart, int y, int x, int z)
498 {
499 return 0.4f;
500 }
501
502 /**
503 * This function is called by any minecart that passes over this rail.
504 * It is called once per update tick that the minecart is on the rail.
505 * @param world The world.
506 * @param cart The cart on the rail.
507 * @param y The rail X coordinate.
508 * @param x The rail Y coordinate.
509 * @param z The rail Z coordinate.
510 */
511 public void onMinecartPass(World world, EntityMinecart cart, int y, int x, int z)
512 {
513 }
514
515 /**
516 * Return true if this rail uses the 4th bit as a power bit.
517 * Avoid using this function when getBasicRailMetadata() can be used instead.
518 * The only reason to use this function is if you wish to change the rails metadata.
519 * @param world The world.
520 * @param x The rail X coordinate.
521 * @param y The rail Y coordinate.
522 * @param z The rail Z coordinate.
523 * @return True if the 4th bit is a power bit.
524 */
525 public boolean hasPowerBit(World world, int x, int y, int z)
526 {
527 return isPowered;
528 }
529 }