001 package net.minecraft.src;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.SideOnly;
005
006 import java.util.ArrayList;
007 import java.util.List;
008 import net.minecraftforge.common.IMinecartCollisionHandler;
009 import net.minecraftforge.common.MinecartRegistry;
010 import net.minecraftforge.common.MinecraftForge;
011 import net.minecraftforge.event.entity.minecart.MinecartCollisionEvent;
012 import net.minecraftforge.event.entity.minecart.MinecartInteractEvent;
013 import net.minecraftforge.event.entity.minecart.MinecartUpdateEvent;
014
015 public class EntityMinecart extends Entity implements IInventory
016 {
017 /** Array of item stacks stored in minecart (for storage minecarts). */
018 protected ItemStack[] cargoItems;
019 protected int fuel;
020 protected boolean field_70499_f;
021
022 /** The type of minecart, 2 for powered, 1 for storage. */
023 public int minecartType;
024 public double pushX;
025 public double pushZ;
026 protected final IUpdatePlayerListBox field_82344_g;
027 protected boolean field_82345_h;
028 protected static final int[][][] field_70500_g = new int[][][] {{{0, 0, -1}, {0, 0, 1}}, {{ -1, 0, 0}, {1, 0, 0}}, {{ -1, -1, 0}, {1, 0, 0}}, {{ -1, 0, 0}, {1, -1, 0}}, {{0, 0, -1}, {0, -1, 1}}, {{0, -1, -1}, {0, 0, 1}}, {{0, 0, 1}, {1, 0, 0}}, {{0, 0, 1}, { -1, 0, 0}}, {{0, 0, -1}, { -1, 0, 0}}, {{0, 0, -1}, {1, 0, 0}}};
029
030 /** appears to be the progress of the turn */
031 protected int turnProgress;
032 protected double minecartX;
033 protected double minecartY;
034 protected double minecartZ;
035 protected double minecartYaw;
036 protected double minecartPitch;
037 @SideOnly(Side.CLIENT)
038 protected double velocityX;
039 @SideOnly(Side.CLIENT)
040 protected double velocityY;
041 @SideOnly(Side.CLIENT)
042 protected double velocityZ;
043
044 /* Forge: Minecart Compatibility Layer Integration. */
045 public static float defaultMaxSpeedRail = 0.4f;
046 public static float defaultMaxSpeedGround = 0.4f;
047 public static float defaultMaxSpeedAirLateral = 0.4f;
048 public static float defaultMaxSpeedAirVertical = -1f;
049 public static double defaultDragRidden = 0.996999979019165D;
050 public static double defaultDragEmpty = 0.9599999785423279D;
051 public static double defaultDragAir = 0.94999998807907104D;
052 protected boolean canUseRail = true;
053 protected boolean canBePushed = true;
054 private static IMinecartCollisionHandler collisionHandler = null;
055
056 /* Instance versions of the above physics properties */
057 protected float maxSpeedRail;
058 protected float maxSpeedGround;
059 protected float maxSpeedAirLateral;
060 protected float maxSpeedAirVertical;
061 protected double dragAir;
062
063 public EntityMinecart(World par1World)
064 {
065 super(par1World);
066 this.cargoItems = new ItemStack[36];
067 this.fuel = 0;
068 this.field_70499_f = false;
069 this.field_82345_h = true;
070 this.preventEntitySpawning = true;
071 this.setSize(0.98F, 0.7F);
072 this.yOffset = this.height / 2.0F;
073 this.field_82344_g = par1World != null ? par1World.func_82735_a(this) : null;
074
075 maxSpeedRail = defaultMaxSpeedRail;
076 maxSpeedGround = defaultMaxSpeedGround;
077 maxSpeedAirLateral = defaultMaxSpeedAirLateral;
078 maxSpeedAirVertical = defaultMaxSpeedAirVertical;
079 dragAir = defaultDragAir;
080 }
081
082 public EntityMinecart(World world, int type)
083 {
084 this(world);
085 minecartType = type;
086 }
087
088 /**
089 * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
090 * prevent them from trampling crops
091 */
092 protected boolean canTriggerWalking()
093 {
094 return false;
095 }
096
097 protected void entityInit()
098 {
099 this.dataWatcher.addObject(16, new Byte((byte)0));
100 this.dataWatcher.addObject(17, new Integer(0));
101 this.dataWatcher.addObject(18, new Integer(1));
102 this.dataWatcher.addObject(19, new Integer(0));
103 }
104
105 /**
106 * Returns a boundingBox used to collide the entity with other entities and blocks. This enables the entity to be
107 * pushable on contact, like boats or minecarts.
108 */
109 public AxisAlignedBB getCollisionBox(Entity par1Entity)
110 {
111 if (getCollisionHandler() != null)
112 {
113 return getCollisionHandler().getCollisionBox(this, par1Entity);
114 }
115 return par1Entity.canBePushed() ? par1Entity.boundingBox : null;
116 }
117
118 /**
119 * returns the bounding box for this entity
120 */
121 public AxisAlignedBB getBoundingBox()
122 {
123 if (getCollisionHandler() != null)
124 {
125 return getCollisionHandler().getBoundingBox(this);
126 }
127 return null;
128 }
129
130 /**
131 * Returns true if this entity should push and be pushed by other entities when colliding.
132 */
133 public boolean canBePushed()
134 {
135 return canBePushed;
136 }
137
138 public EntityMinecart(World par1World, double par2, double par4, double par6, int par8)
139 {
140 this(par1World);
141 this.setPosition(par2, par4 + (double)this.yOffset, par6);
142 this.motionX = 0.0D;
143 this.motionY = 0.0D;
144 this.motionZ = 0.0D;
145 this.prevPosX = par2;
146 this.prevPosY = par4;
147 this.prevPosZ = par6;
148 this.minecartType = par8;
149 }
150
151 /**
152 * Returns the Y offset from the entity's position for any entity riding this one.
153 */
154 public double getMountedYOffset()
155 {
156 return (double)this.height * 0.0D - 0.30000001192092896D;
157 }
158
159 /**
160 * Called when the entity is attacked.
161 */
162 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
163 {
164 if (!this.worldObj.isRemote && !this.isDead)
165 {
166 if (this.func_85032_ar())
167 {
168 return false;
169 }
170 else
171 {
172 this.func_70494_i(-this.func_70493_k());
173 this.func_70497_h(10);
174 this.setBeenAttacked();
175 this.setDamage(this.getDamage() + par2 * 10);
176
177 if (par1DamageSource.getEntity() instanceof EntityPlayer && ((EntityPlayer)par1DamageSource.getEntity()).capabilities.isCreativeMode)
178 {
179 this.setDamage(100);
180 }
181
182 if (this.getDamage() > 40)
183 {
184 if (this.riddenByEntity != null)
185 {
186 this.riddenByEntity.mountEntity(this);
187 }
188
189 this.setDead();
190 dropCartAsItem();
191 }
192
193 return true;
194 }
195 }
196 else
197 {
198 return true;
199 }
200 }
201
202 @SideOnly(Side.CLIENT)
203
204 /**
205 * Setups the entity to do the hurt animation. Only used by packets in multiplayer.
206 */
207 public void performHurtAnimation()
208 {
209 this.func_70494_i(-this.func_70493_k());
210 this.func_70497_h(10);
211 this.setDamage(this.getDamage() + this.getDamage() * 10);
212 }
213
214 /**
215 * Returns true if other Entities should be prevented from moving through this Entity.
216 */
217 public boolean canBeCollidedWith()
218 {
219 return !this.isDead;
220 }
221
222 /**
223 * Will get destroyed next tick.
224 */
225 public void setDead()
226 {
227 if (this.field_82345_h)
228 {
229 for (int var1 = 0; var1 < this.getSizeInventory(); ++var1)
230 {
231 ItemStack var2 = this.getStackInSlot(var1);
232
233 if (var2 != null)
234 {
235 float var3 = this.rand.nextFloat() * 0.8F + 0.1F;
236 float var4 = this.rand.nextFloat() * 0.8F + 0.1F;
237 float var5 = this.rand.nextFloat() * 0.8F + 0.1F;
238
239 while (var2.stackSize > 0)
240 {
241 int var6 = this.rand.nextInt(21) + 10;
242
243 if (var6 > var2.stackSize)
244 {
245 var6 = var2.stackSize;
246 }
247
248 var2.stackSize -= var6;
249 EntityItem var7 = new EntityItem(this.worldObj, this.posX + (double)var3, this.posY + (double)var4, this.posZ + (double)var5, new ItemStack(var2.itemID, var6, var2.getItemDamage()));
250
251 if (var2.hasTagCompound())
252 {
253 var7.item.setTagCompound((NBTTagCompound)var2.getTagCompound().copy());
254 }
255
256 float var8 = 0.05F;
257 var7.motionX = (double)((float)this.rand.nextGaussian() * var8);
258 var7.motionY = (double)((float)this.rand.nextGaussian() * var8 + 0.2F);
259 var7.motionZ = (double)((float)this.rand.nextGaussian() * var8);
260 this.worldObj.spawnEntityInWorld(var7);
261 }
262 }
263 }
264 }
265
266 super.setDead();
267
268 if (this.field_82344_g != null)
269 {
270 this.field_82344_g.update();
271 }
272 }
273
274 /**
275 * Teleports the entity to another dimension. Params: Dimension number to teleport to
276 */
277 public void travelToDimension(int par1)
278 {
279 this.field_82345_h = false;
280 super.travelToDimension(par1);
281 }
282
283 /**
284 * Called to update the entity's position/logic.
285 */
286 public void onUpdate()
287 {
288 if (this.field_82344_g != null)
289 {
290 this.field_82344_g.update();
291 }
292
293 if (this.func_70496_j() > 0)
294 {
295 this.func_70497_h(this.func_70496_j() - 1);
296 }
297
298 if (this.getDamage() > 0)
299 {
300 this.setDamage(this.getDamage() - 1);
301 }
302
303 if (this.posY < -64.0D)
304 {
305 this.kill();
306 }
307
308 if (this.isMinecartPowered() && this.rand.nextInt(4) == 0 && minecartType == 2 && getClass() == EntityMinecart.class)
309 {
310 this.worldObj.spawnParticle("largesmoke", this.posX, this.posY + 0.8D, this.posZ, 0.0D, 0.0D, 0.0D);
311 }
312
313 if (this.worldObj.isRemote)
314 {
315 if (this.turnProgress > 0)
316 {
317 double var45 = this.posX + (this.minecartX - this.posX) / (double)this.turnProgress;
318 double var46 = this.posY + (this.minecartY - this.posY) / (double)this.turnProgress;
319 double var5 = this.posZ + (this.minecartZ - this.posZ) / (double)this.turnProgress;
320 double var7 = MathHelper.wrapAngleTo180_double(this.minecartYaw - (double)this.rotationYaw);
321 this.rotationYaw = (float)((double)this.rotationYaw + var7 / (double)this.turnProgress);
322 this.rotationPitch = (float)((double)this.rotationPitch + (this.minecartPitch - (double)this.rotationPitch) / (double)this.turnProgress);
323 --this.turnProgress;
324 this.setPosition(var45, var46, var5);
325 this.setRotation(this.rotationYaw, this.rotationPitch);
326 }
327 else
328 {
329 this.setPosition(this.posX, this.posY, this.posZ);
330 this.setRotation(this.rotationYaw, this.rotationPitch);
331 }
332 }
333 else
334 {
335 this.prevPosX = this.posX;
336 this.prevPosY = this.posY;
337 this.prevPosZ = this.posZ;
338 this.motionY -= 0.03999999910593033D;
339 int var1 = MathHelper.floor_double(this.posX);
340 int var2 = MathHelper.floor_double(this.posY);
341 int var3 = MathHelper.floor_double(this.posZ);
342
343 if (BlockRail.isRailBlockAt(this.worldObj, var1, var2 - 1, var3))
344 {
345 --var2;
346 }
347
348 double var4 = 0.4D;
349 double var6 = 0.0078125D;
350 int var8 = this.worldObj.getBlockId(var1, var2, var3);
351
352 if (canUseRail() && BlockRail.isRailBlock(var8))
353 {
354 this.fallDistance = 0.0F;
355 Vec3 var9 = this.func_70489_a(this.posX, this.posY, this.posZ);
356 int var10 = ((BlockRail)Block.blocksList[var8]).getBasicRailMetadata(worldObj, this, var1, var2, var3);
357 this.posY = (double)var2;
358 boolean var11 = false;
359 boolean var12 = false;
360
361 if (var8 == Block.railPowered.blockID)
362 {
363 var11 = (worldObj.getBlockMetadata(var1, var2, var3) & 8) != 0;
364 var12 = !var11;
365 }
366
367 if (((BlockRail)Block.blocksList[var8]).isPowered())
368 {
369 var10 &= 7;
370 }
371
372 if (var10 >= 2 && var10 <= 5)
373 {
374 this.posY = (double)(var2 + 1);
375 }
376
377 adjustSlopeVelocities(var10);
378
379 int[][] var13 = field_70500_g[var10];
380 double var14 = (double)(var13[1][0] - var13[0][0]);
381 double var16 = (double)(var13[1][2] - var13[0][2]);
382 double var18 = Math.sqrt(var14 * var14 + var16 * var16);
383 double var20 = this.motionX * var14 + this.motionZ * var16;
384
385 if (var20 < 0.0D)
386 {
387 var14 = -var14;
388 var16 = -var16;
389 }
390
391 double var22 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
392 this.motionX = var22 * var14 / var18;
393 this.motionZ = var22 * var16 / var18;
394 double var24;
395 double var26;
396
397 if (this.riddenByEntity != null)
398 {
399 var24 = this.riddenByEntity.motionX * this.riddenByEntity.motionX + this.riddenByEntity.motionZ * this.riddenByEntity.motionZ;
400 var26 = this.motionX * this.motionX + this.motionZ * this.motionZ;
401
402 if (var24 > 1.0E-4D && var26 < 0.01D)
403 {
404 this.motionX += this.riddenByEntity.motionX * 0.1D;
405 this.motionZ += this.riddenByEntity.motionZ * 0.1D;
406 var12 = false;
407 }
408 }
409
410 if (var12 && shouldDoRailFunctions())
411 {
412 var24 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
413
414 if (var24 < 0.03D)
415 {
416 this.motionX *= 0.0D;
417 this.motionY *= 0.0D;
418 this.motionZ *= 0.0D;
419 }
420 else
421 {
422 this.motionX *= 0.5D;
423 this.motionY *= 0.0D;
424 this.motionZ *= 0.5D;
425 }
426 }
427
428 var24 = 0.0D;
429 var26 = (double)var1 + 0.5D + (double)var13[0][0] * 0.5D;
430 double var28 = (double)var3 + 0.5D + (double)var13[0][2] * 0.5D;
431 double var30 = (double)var1 + 0.5D + (double)var13[1][0] * 0.5D;
432 double var32 = (double)var3 + 0.5D + (double)var13[1][2] * 0.5D;
433 var14 = var30 - var26;
434 var16 = var32 - var28;
435 double var34;
436 double var36;
437
438 if (var14 == 0.0D)
439 {
440 this.posX = (double)var1 + 0.5D;
441 var24 = this.posZ - (double)var3;
442 }
443 else if (var16 == 0.0D)
444 {
445 this.posZ = (double)var3 + 0.5D;
446 var24 = this.posX - (double)var1;
447 }
448 else
449 {
450 var34 = this.posX - var26;
451 var36 = this.posZ - var28;
452 var24 = (var34 * var14 + var36 * var16) * 2.0D;
453 }
454
455 this.posX = var26 + var14 * var24;
456 this.posZ = var28 + var16 * var24;
457 this.setPosition(this.posX, this.posY + (double)this.yOffset, this.posZ);
458
459 moveMinecartOnRail(var1, var2, var3);
460
461 if (var13[0][1] != 0 && MathHelper.floor_double(this.posX) - var1 == var13[0][0] && MathHelper.floor_double(this.posZ) - var3 == var13[0][2])
462 {
463 this.setPosition(this.posX, this.posY + (double)var13[0][1], this.posZ);
464 }
465 else if (var13[1][1] != 0 && MathHelper.floor_double(this.posX) - var1 == var13[1][0] && MathHelper.floor_double(this.posZ) - var3 == var13[1][2])
466 {
467 this.setPosition(this.posX, this.posY + (double)var13[1][1], this.posZ);
468 }
469
470 applyDragAndPushForces();
471
472 Vec3 var52 = this.func_70489_a(this.posX, this.posY, this.posZ);
473
474 if (var52 != null && var9 != null)
475 {
476 double var39 = (var9.yCoord - var52.yCoord) * 0.05D;
477 var22 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
478
479 if (var22 > 0.0D)
480 {
481 this.motionX = this.motionX / var22 * (var22 + var39);
482 this.motionZ = this.motionZ / var22 * (var22 + var39);
483 }
484
485 this.setPosition(this.posX, var52.yCoord, this.posZ);
486 }
487
488 int var51 = MathHelper.floor_double(this.posX);
489 int var53 = MathHelper.floor_double(this.posZ);
490
491 if (var51 != var1 || var53 != var3)
492 {
493 var22 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
494 this.motionX = var22 * (double)(var51 - var1);
495 this.motionZ = var22 * (double)(var53 - var3);
496 }
497
498 double var41;
499
500 updatePushForces();
501
502 if(shouldDoRailFunctions())
503 {
504 ((BlockRail)Block.blocksList[var8]).onMinecartPass(worldObj, this, var1, var2, var3);
505 }
506
507 if (var11 && shouldDoRailFunctions())
508 {
509 var41 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
510
511 if (var41 > 0.01D)
512 {
513 double var43 = 0.06D;
514 this.motionX += this.motionX / var41 * var43;
515 this.motionZ += this.motionZ / var41 * var43;
516 }
517 else if (var10 == 1)
518 {
519 if (this.worldObj.isBlockNormalCube(var1 - 1, var2, var3))
520 {
521 this.motionX = 0.02D;
522 }
523 else if (this.worldObj.isBlockNormalCube(var1 + 1, var2, var3))
524 {
525 this.motionX = -0.02D;
526 }
527 }
528 else if (var10 == 0)
529 {
530 if (this.worldObj.isBlockNormalCube(var1, var2, var3 - 1))
531 {
532 this.motionZ = 0.02D;
533 }
534 else if (this.worldObj.isBlockNormalCube(var1, var2, var3 + 1))
535 {
536 this.motionZ = -0.02D;
537 }
538 }
539 }
540 }
541 else
542 {
543 moveMinecartOffRail(var1, var2, var3);
544 }
545
546 this.doBlockCollisions();
547 this.rotationPitch = 0.0F;
548 double var47 = this.prevPosX - this.posX;
549 double var48 = this.prevPosZ - this.posZ;
550
551 if (var47 * var47 + var48 * var48 > 0.001D)
552 {
553 this.rotationYaw = (float)(Math.atan2(var48, var47) * 180.0D / Math.PI);
554
555 if (this.field_70499_f)
556 {
557 this.rotationYaw += 180.0F;
558 }
559 }
560
561 double var49 = (double)MathHelper.wrapAngleTo180_float(this.rotationYaw - this.prevRotationYaw);
562
563 if (var49 < -170.0D || var49 >= 170.0D)
564 {
565 this.rotationYaw += 180.0F;
566 this.field_70499_f = !this.field_70499_f;
567 }
568
569 this.setRotation(this.rotationYaw, this.rotationPitch);
570
571 AxisAlignedBB box = null;
572 if (getCollisionHandler() != null)
573 {
574 box = getCollisionHandler().getMinecartCollisionBox(this);
575 }
576 else
577 {
578 box = boundingBox.expand(0.2D, 0.0D, 0.2D);
579 }
580
581 List var15 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, box);
582
583 if (var15 != null && !var15.isEmpty())
584 {
585 for (int var50 = 0; var50 < var15.size(); ++var50)
586 {
587 Entity var17 = (Entity)var15.get(var50);
588
589 if (var17 != this.riddenByEntity && var17.canBePushed() && var17 instanceof EntityMinecart)
590 {
591 var17.applyEntityCollision(this);
592 }
593 }
594 }
595
596 if (this.riddenByEntity != null && this.riddenByEntity.isDead)
597 {
598 if (this.riddenByEntity.ridingEntity == this)
599 {
600 this.riddenByEntity.ridingEntity = null;
601 }
602
603 this.riddenByEntity = null;
604 }
605
606 updateFuel();
607 MinecraftForge.EVENT_BUS.post(new MinecartUpdateEvent(this, var1, var2, var3));
608 }
609 }
610
611 @SideOnly(Side.CLIENT)
612 public Vec3 func_70495_a(double par1, double par3, double par5, double par7)
613 {
614 int var9 = MathHelper.floor_double(par1);
615 int var10 = MathHelper.floor_double(par3);
616 int var11 = MathHelper.floor_double(par5);
617
618 if (BlockRail.isRailBlockAt(this.worldObj, var9, var10 - 1, var11))
619 {
620 --var10;
621 }
622
623 int var12 = this.worldObj.getBlockId(var9, var10, var11);
624
625 if (!BlockRail.isRailBlock(var12))
626 {
627 return null;
628 }
629 else
630 {
631 int var13 = ((BlockRail)Block.blocksList[var12]).getBasicRailMetadata(worldObj, this, var9, var10, var11);
632
633 par3 = (double)var10;
634
635 if (var13 >= 2 && var13 <= 5)
636 {
637 par3 = (double)(var10 + 1);
638 }
639
640 int[][] var14 = field_70500_g[var13];
641 double var15 = (double)(var14[1][0] - var14[0][0]);
642 double var17 = (double)(var14[1][2] - var14[0][2]);
643 double var19 = Math.sqrt(var15 * var15 + var17 * var17);
644 var15 /= var19;
645 var17 /= var19;
646 par1 += var15 * par7;
647 par5 += var17 * par7;
648
649 if (var14[0][1] != 0 && MathHelper.floor_double(par1) - var9 == var14[0][0] && MathHelper.floor_double(par5) - var11 == var14[0][2])
650 {
651 par3 += (double)var14[0][1];
652 }
653 else if (var14[1][1] != 0 && MathHelper.floor_double(par1) - var9 == var14[1][0] && MathHelper.floor_double(par5) - var11 == var14[1][2])
654 {
655 par3 += (double)var14[1][1];
656 }
657
658 return this.func_70489_a(par1, par3, par5);
659 }
660 }
661
662 public Vec3 func_70489_a(double par1, double par3, double par5)
663 {
664 int var7 = MathHelper.floor_double(par1);
665 int var8 = MathHelper.floor_double(par3);
666 int var9 = MathHelper.floor_double(par5);
667
668 if (BlockRail.isRailBlockAt(this.worldObj, var7, var8 - 1, var9))
669 {
670 --var8;
671 }
672
673 int var10 = this.worldObj.getBlockId(var7, var8, var9);
674
675 if (BlockRail.isRailBlock(var10))
676 {
677 int var11 = ((BlockRail)Block.blocksList[var10]).getBasicRailMetadata(worldObj, this, var7, var8, var9);
678 par3 = (double)var8;
679
680 if (var11 >= 2 && var11 <= 5)
681 {
682 par3 = (double)(var8 + 1);
683 }
684
685 int[][] var12 = field_70500_g[var11];
686 double var13 = 0.0D;
687 double var15 = (double)var7 + 0.5D + (double)var12[0][0] * 0.5D;
688 double var17 = (double)var8 + 0.5D + (double)var12[0][1] * 0.5D;
689 double var19 = (double)var9 + 0.5D + (double)var12[0][2] * 0.5D;
690 double var21 = (double)var7 + 0.5D + (double)var12[1][0] * 0.5D;
691 double var23 = (double)var8 + 0.5D + (double)var12[1][1] * 0.5D;
692 double var25 = (double)var9 + 0.5D + (double)var12[1][2] * 0.5D;
693 double var27 = var21 - var15;
694 double var29 = (var23 - var17) * 2.0D;
695 double var31 = var25 - var19;
696
697 if (var27 == 0.0D)
698 {
699 par1 = (double)var7 + 0.5D;
700 var13 = par5 - (double)var9;
701 }
702 else if (var31 == 0.0D)
703 {
704 par5 = (double)var9 + 0.5D;
705 var13 = par1 - (double)var7;
706 }
707 else
708 {
709 double var33 = par1 - var15;
710 double var35 = par5 - var19;
711 var13 = (var33 * var27 + var35 * var31) * 2.0D;
712 }
713
714 par1 = var15 + var27 * var13;
715 par3 = var17 + var29 * var13;
716 par5 = var19 + var31 * var13;
717
718 if (var29 < 0.0D)
719 {
720 ++par3;
721 }
722
723 if (var29 > 0.0D)
724 {
725 par3 += 0.5D;
726 }
727
728 return this.worldObj.getWorldVec3Pool().getVecFromPool(par1, par3, par5);
729 }
730 else
731 {
732 return null;
733 }
734 }
735
736 /**
737 * (abstract) Protected helper method to write subclass entity data to NBT.
738 */
739 protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
740 {
741 par1NBTTagCompound.setInteger("Type", this.minecartType);
742
743 if (isPoweredCart())
744 {
745 par1NBTTagCompound.setDouble("PushX", this.pushX);
746 par1NBTTagCompound.setDouble("PushZ", this.pushZ);
747 par1NBTTagCompound.setInteger("Fuel", this.fuel);
748 }
749
750 if (getSizeInventory() > 0)
751 {
752 NBTTagList var2 = new NBTTagList();
753
754 for (int var3 = 0; var3 < this.cargoItems.length; ++var3)
755 {
756 if (this.cargoItems[var3] != null)
757 {
758 NBTTagCompound var4 = new NBTTagCompound();
759 var4.setByte("Slot", (byte)var3);
760 this.cargoItems[var3].writeToNBT(var4);
761 var2.appendTag(var4);
762 }
763 }
764
765 par1NBTTagCompound.setTag("Items", var2);
766 }
767 }
768
769 /**
770 * (abstract) Protected helper method to read subclass entity data from NBT.
771 */
772 protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
773 {
774 this.minecartType = par1NBTTagCompound.getInteger("Type");
775
776 if (isPoweredCart())
777 {
778 this.pushX = par1NBTTagCompound.getDouble("PushX");
779 this.pushZ = par1NBTTagCompound.getDouble("PushZ");
780 try
781 {
782 this.fuel = par1NBTTagCompound.getInteger("Fuel");
783 }
784 catch (ClassCastException e)
785 {
786 this.fuel = par1NBTTagCompound.getShort("Fuel");
787 }
788 }
789
790 if (getSizeInventory() > 0)
791 {
792 NBTTagList var2 = par1NBTTagCompound.getTagList("Items");
793 this.cargoItems = new ItemStack[this.getSizeInventory()];
794
795 for (int var3 = 0; var3 < var2.tagCount(); ++var3)
796 {
797 NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
798 int var5 = var4.getByte("Slot") & 255;
799
800 if (var5 >= 0 && var5 < this.cargoItems.length)
801 {
802 this.cargoItems[var5] = ItemStack.loadItemStackFromNBT(var4);
803 }
804 }
805 }
806 }
807
808 @SideOnly(Side.CLIENT)
809 public float getShadowSize()
810 {
811 return 0.0F;
812 }
813
814 /**
815 * Applies a velocity to each of the entities pushing them away from each other. Args: entity
816 */
817 public void applyEntityCollision(Entity par1Entity)
818 {
819 MinecraftForge.EVENT_BUS.post(new MinecartCollisionEvent(this, par1Entity));
820 if (getCollisionHandler() != null)
821 {
822 getCollisionHandler().onEntityCollision(this, par1Entity);
823 return;
824 }
825 if (!this.worldObj.isRemote)
826 {
827 if (par1Entity != this.riddenByEntity)
828 {
829 if (par1Entity instanceof EntityLiving && !(par1Entity instanceof EntityPlayer) && !(par1Entity instanceof EntityIronGolem) && canBeRidden() && this.motionX * this.motionX + this.motionZ * this.motionZ > 0.01D && this.riddenByEntity == null && par1Entity.ridingEntity == null)
830 {
831 par1Entity.mountEntity(this);
832 }
833
834 double var2 = par1Entity.posX - this.posX;
835 double var4 = par1Entity.posZ - this.posZ;
836 double var6 = var2 * var2 + var4 * var4;
837
838 if (var6 >= 9.999999747378752E-5D)
839 {
840 var6 = (double)MathHelper.sqrt_double(var6);
841 var2 /= var6;
842 var4 /= var6;
843 double var8 = 1.0D / var6;
844
845 if (var8 > 1.0D)
846 {
847 var8 = 1.0D;
848 }
849
850 var2 *= var8;
851 var4 *= var8;
852 var2 *= 0.10000000149011612D;
853 var4 *= 0.10000000149011612D;
854 var2 *= (double)(1.0F - this.entityCollisionReduction);
855 var4 *= (double)(1.0F - this.entityCollisionReduction);
856 var2 *= 0.5D;
857 var4 *= 0.5D;
858
859 if (par1Entity instanceof EntityMinecart)
860 {
861 double var10 = par1Entity.posX - this.posX;
862 double var12 = par1Entity.posZ - this.posZ;
863 Vec3 var14 = this.worldObj.getWorldVec3Pool().getVecFromPool(var10, 0.0D, var12).normalize();
864 Vec3 var15 = this.worldObj.getWorldVec3Pool().getVecFromPool((double)MathHelper.cos(this.rotationYaw * (float)Math.PI / 180.0F), 0.0D, (double)MathHelper.sin(this.rotationYaw * (float)Math.PI / 180.0F)).normalize();
865 double var16 = Math.abs(var14.dotProduct(var15));
866
867 if (var16 < 0.800000011920929D)
868 {
869 return;
870 }
871
872 double var18 = par1Entity.motionX + this.motionX;
873 double var20 = par1Entity.motionZ + this.motionZ;
874
875 if (((EntityMinecart)par1Entity).isPoweredCart() && !isPoweredCart())
876 {
877 this.motionX *= 0.20000000298023224D;
878 this.motionZ *= 0.20000000298023224D;
879 this.addVelocity(par1Entity.motionX - var2, 0.0D, par1Entity.motionZ - var4);
880 par1Entity.motionX *= 0.949999988079071D;
881 par1Entity.motionZ *= 0.949999988079071D;
882 }
883 else if (!((EntityMinecart)par1Entity).isPoweredCart() && isPoweredCart())
884 {
885 par1Entity.motionX *= 0.20000000298023224D;
886 par1Entity.motionZ *= 0.20000000298023224D;
887 par1Entity.addVelocity(this.motionX + var2, 0.0D, this.motionZ + var4);
888 this.motionX *= 0.949999988079071D;
889 this.motionZ *= 0.949999988079071D;
890 }
891 else
892 {
893 var18 /= 2.0D;
894 var20 /= 2.0D;
895 this.motionX *= 0.20000000298023224D;
896 this.motionZ *= 0.20000000298023224D;
897 this.addVelocity(var18 - var2, 0.0D, var20 - var4);
898 par1Entity.motionX *= 0.20000000298023224D;
899 par1Entity.motionZ *= 0.20000000298023224D;
900 par1Entity.addVelocity(var18 + var2, 0.0D, var20 + var4);
901 }
902 }
903 else
904 {
905 this.addVelocity(-var2, 0.0D, -var4);
906 par1Entity.addVelocity(var2 / 4.0D, 0.0D, var4 / 4.0D);
907 }
908 }
909 }
910 }
911 }
912
913 /**
914 * Returns the number of slots in the inventory.
915 */
916 public int getSizeInventory()
917 {
918 return (minecartType == 1 && getClass() == EntityMinecart.class ? 27 : 0);
919 }
920
921 /**
922 * Returns the stack in slot i
923 */
924 public ItemStack getStackInSlot(int par1)
925 {
926 return this.cargoItems[par1];
927 }
928
929 /**
930 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
931 * new stack.
932 */
933 public ItemStack decrStackSize(int par1, int par2)
934 {
935 if (this.cargoItems[par1] != null)
936 {
937 ItemStack var3;
938
939 if (this.cargoItems[par1].stackSize <= par2)
940 {
941 var3 = this.cargoItems[par1];
942 this.cargoItems[par1] = null;
943 return var3;
944 }
945 else
946 {
947 var3 = this.cargoItems[par1].splitStack(par2);
948
949 if (this.cargoItems[par1].stackSize == 0)
950 {
951 this.cargoItems[par1] = null;
952 }
953
954 return var3;
955 }
956 }
957 else
958 {
959 return null;
960 }
961 }
962
963 /**
964 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
965 * like when you close a workbench GUI.
966 */
967 public ItemStack getStackInSlotOnClosing(int par1)
968 {
969 if (this.cargoItems[par1] != null)
970 {
971 ItemStack var2 = this.cargoItems[par1];
972 this.cargoItems[par1] = null;
973 return var2;
974 }
975 else
976 {
977 return null;
978 }
979 }
980
981 /**
982 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
983 */
984 public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
985 {
986 this.cargoItems[par1] = par2ItemStack;
987
988 if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
989 {
990 par2ItemStack.stackSize = this.getInventoryStackLimit();
991 }
992 }
993
994 /**
995 * Returns the name of the inventory.
996 */
997 public String getInvName()
998 {
999 return "container.minecart";
1000 }
1001
1002 /**
1003 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
1004 * this more of a set than a get?*
1005 */
1006 public int getInventoryStackLimit()
1007 {
1008 return 64;
1009 }
1010
1011 /**
1012 * Called when an the contents of an Inventory change, usually
1013 */
1014 public void onInventoryChanged() {}
1015
1016 /**
1017 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
1018 */
1019 public boolean interact(EntityPlayer par1EntityPlayer)
1020 {
1021 if (MinecraftForge.EVENT_BUS.post(new MinecartInteractEvent(this, par1EntityPlayer)))
1022 {
1023 return true;
1024 }
1025
1026 if (canBeRidden())
1027 {
1028 if (this.riddenByEntity != null && this.riddenByEntity instanceof EntityPlayer && this.riddenByEntity != par1EntityPlayer)
1029 {
1030 return true;
1031 }
1032
1033 if (!this.worldObj.isRemote)
1034 {
1035 par1EntityPlayer.mountEntity(this);
1036 }
1037 }
1038 else if (getSizeInventory() > 0)
1039 {
1040 if (!this.worldObj.isRemote)
1041 {
1042 par1EntityPlayer.displayGUIChest(this);
1043 }
1044 }
1045 else if (this.minecartType == 2 && getClass() == EntityMinecart.class)
1046 {
1047 ItemStack var2 = par1EntityPlayer.inventory.getCurrentItem();
1048
1049 if (var2 != null && var2.itemID == Item.coal.shiftedIndex)
1050 {
1051 if (--var2.stackSize == 0)
1052 {
1053 par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null);
1054 }
1055
1056 this.fuel += 3600;
1057 }
1058
1059 this.pushX = this.posX - par1EntityPlayer.posX;
1060 this.pushZ = this.posZ - par1EntityPlayer.posZ;
1061 }
1062
1063 return true;
1064 }
1065
1066 @SideOnly(Side.CLIENT)
1067
1068 /**
1069 * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX,
1070 * posY, posZ, yaw, pitch
1071 */
1072 public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
1073 {
1074 this.minecartX = par1;
1075 this.minecartY = par3;
1076 this.minecartZ = par5;
1077 this.minecartYaw = (double)par7;
1078 this.minecartPitch = (double)par8;
1079 this.turnProgress = par9 + 2;
1080 this.motionX = this.velocityX;
1081 this.motionY = this.velocityY;
1082 this.motionZ = this.velocityZ;
1083 }
1084
1085 /**
1086 * Do not make give this method the name canInteractWith because it clashes with Container
1087 */
1088 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
1089 {
1090 return this.isDead ? false : par1EntityPlayer.getDistanceSqToEntity(this) <= 64.0D;
1091 }
1092
1093 @SideOnly(Side.CLIENT)
1094
1095 /**
1096 * Sets the velocity to the args. Args: x, y, z
1097 */
1098 public void setVelocity(double par1, double par3, double par5)
1099 {
1100 this.velocityX = this.motionX = par1;
1101 this.velocityY = this.motionY = par3;
1102 this.velocityZ = this.motionZ = par5;
1103 }
1104
1105 /**
1106 * Is this minecart powered (Fuel > 0)
1107 */
1108 public boolean isMinecartPowered()
1109 {
1110 return (this.dataWatcher.getWatchableObjectByte(16) & 1) != 0;
1111 }
1112
1113 /**
1114 * Set if this minecart is powered (Fuel > 0)
1115 */
1116 protected void setMinecartPowered(boolean par1)
1117 {
1118 if (par1)
1119 {
1120 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(this.dataWatcher.getWatchableObjectByte(16) | 1)));
1121 }
1122 else
1123 {
1124 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(this.dataWatcher.getWatchableObjectByte(16) & -2)));
1125 }
1126 }
1127
1128 public void openChest() {}
1129
1130 public void closeChest() {}
1131
1132 /**
1133 * Sets the current amount of damage the minecart has taken. Decreases over time. The cart breaks when this is over
1134 * 40.
1135 */
1136 public void setDamage(int par1)
1137 {
1138 this.dataWatcher.updateObject(19, Integer.valueOf(par1));
1139 }
1140
1141 /**
1142 * Gets the current amount of damage the minecart has taken. Decreases over time. The cart breaks when this is over
1143 * 40.
1144 */
1145 public int getDamage()
1146 {
1147 return this.dataWatcher.getWatchableObjectInt(19);
1148 }
1149
1150 public void func_70497_h(int par1)
1151 {
1152 this.dataWatcher.updateObject(17, Integer.valueOf(par1));
1153 }
1154
1155 public int func_70496_j()
1156 {
1157 return this.dataWatcher.getWatchableObjectInt(17);
1158 }
1159
1160 public void func_70494_i(int par1)
1161 {
1162 this.dataWatcher.updateObject(18, Integer.valueOf(par1));
1163 }
1164
1165 public int func_70493_k()
1166 {
1167 return this.dataWatcher.getWatchableObjectInt(18);
1168 }
1169
1170 /**
1171 * Drops the cart as a item. The exact item dropped is defined by getItemDropped().
1172 */
1173 public void dropCartAsItem()
1174 {
1175 for(ItemStack item : getItemsDropped())
1176 {
1177 entityDropItem(item, 0);
1178 }
1179 }
1180
1181 /**
1182 * Override this to define which items your cart drops when broken.
1183 * This does not include items contained in the inventory,
1184 * that is handled elsewhere.
1185 * @return A list of items dropped.
1186 */
1187 public List<ItemStack> getItemsDropped()
1188 {
1189 List<ItemStack> items = new ArrayList<ItemStack>();
1190 items.add(new ItemStack(Item.minecartEmpty));
1191
1192 switch(minecartType)
1193 {
1194 case 1:
1195 items.add(new ItemStack(Block.chest));
1196 break;
1197 case 2:
1198 items.add(new ItemStack(Block.stoneOvenIdle));
1199 break;
1200 }
1201 return items;
1202 }
1203
1204 /**
1205 * This function returns an ItemStack that represents this cart.
1206 * This should be an ItemStack that can be used by the player to place the cart.
1207 * This is the item that was registered with the cart via the registerMinecart function,
1208 * but is not necessary the item the cart drops when destroyed.
1209 * @return An ItemStack that can be used to place the cart.
1210 */
1211 public ItemStack getCartItem()
1212 {
1213 return MinecartRegistry.getItemForCart(this);
1214 }
1215
1216 /**
1217 * Returns true if this cart is self propelled.
1218 * @return True if powered.
1219 */
1220 public boolean isPoweredCart()
1221 {
1222 return minecartType == 2 && getClass() == EntityMinecart.class;
1223 }
1224
1225 /**
1226 * Returns true if this cart is a storage cart
1227 * Some carts may have inventories but not be storage carts
1228 * and some carts without inventories may be storage carts.
1229 * @return True if this cart should be classified as a storage cart.
1230 */
1231 public boolean isStorageCart()
1232 {
1233 return minecartType == 1 && getClass() == EntityMinecart.class;
1234 }
1235
1236 /**
1237 * Returns true if this cart can be ridden by an Entity.
1238 * @return True if this cart can be ridden.
1239 */
1240 public boolean canBeRidden()
1241 {
1242 if(minecartType == 0 && getClass() == EntityMinecart.class)
1243 {
1244 return true;
1245 }
1246 return false;
1247 }
1248
1249 /**
1250 * Returns true if this cart can currently use rails.
1251 * This function is mainly used to gracefully detach a minecart from a rail.
1252 * @return True if the minecart can use rails.
1253 */
1254 public boolean canUseRail()
1255 {
1256 return canUseRail;
1257 }
1258
1259 /**
1260 * Set whether the minecart can use rails.
1261 * This function is mainly used to gracefully detach a minecart from a rail.
1262 * @param use Whether the minecart can currently use rails.
1263 */
1264 public void setCanUseRail(boolean use)
1265 {
1266 canUseRail = use;
1267 }
1268
1269 /**
1270 * Return false if this cart should not call IRail.onMinecartPass() and should ignore Powered Rails.
1271 * @return True if this cart should call IRail.onMinecartPass().
1272 */
1273 public boolean shouldDoRailFunctions()
1274 {
1275 return true;
1276 }
1277
1278 /**
1279 * Simply returns the minecartType variable.
1280 * @return minecartType
1281 */
1282 public int getMinecartType()
1283 {
1284 return minecartType;
1285 }
1286
1287 /**
1288 * Gets the current global Minecart Collision handler if none
1289 * is registered, returns null
1290 * @return The collision handler or null
1291 */
1292 public static IMinecartCollisionHandler getCollisionHandler()
1293 {
1294 return collisionHandler;
1295 }
1296
1297 /**
1298 * Sets the global Minecart Collision handler, overwrites any
1299 * that is currently set.
1300 * @param handler The new handler
1301 */
1302 public static void setCollisionHandler(IMinecartCollisionHandler handler)
1303 {
1304 collisionHandler = handler;
1305 }
1306
1307 /**
1308 * Carts should return their drag factor here
1309 * @return The drag rate.
1310 */
1311 protected double getDrag()
1312 {
1313 return riddenByEntity != null ? defaultDragRidden : defaultDragEmpty;
1314 }
1315
1316 /**
1317 * Moved to allow overrides.
1318 * This code applies drag and updates push forces.
1319 */
1320 protected void applyDragAndPushForces()
1321 {
1322 if(isPoweredCart())
1323 {
1324 double d27 = MathHelper.sqrt_double(pushX * pushX + pushZ * pushZ);
1325 if(d27 > 0.01D)
1326 {
1327 pushX /= d27;
1328 pushZ /= d27;
1329 double d29 = 0.04;
1330 motionX *= 0.8D;
1331 motionY *= 0.0D;
1332 motionZ *= 0.8D;
1333 motionX += pushX * d29;
1334 motionZ += pushZ * d29;
1335 }
1336 else
1337 {
1338 motionX *= 0.9D;
1339 motionY *= 0.0D;
1340 motionZ *= 0.9D;
1341 }
1342 }
1343 motionX *= getDrag();
1344 motionY *= 0.0D;
1345 motionZ *= getDrag();
1346 }
1347
1348 /**
1349 * Moved to allow overrides.
1350 * This code updates push forces.
1351 */
1352 protected void updatePushForces()
1353 {
1354 if(isPoweredCart())
1355 {
1356 double push = MathHelper.sqrt_double(pushX * pushX + pushZ * pushZ);
1357 if(push > 0.01D && motionX * motionX + motionZ * motionZ > 0.001D)
1358 {
1359 pushX /= push;
1360 pushZ /= push;
1361 if(pushX * motionX + pushZ * motionZ < 0.0D)
1362 {
1363 pushX = 0.0D;
1364 pushZ = 0.0D;
1365 }
1366 else
1367 {
1368 pushX = motionX;
1369 pushZ = motionZ;
1370 }
1371 }
1372 }
1373 }
1374
1375 /**
1376 * Moved to allow overrides.
1377 * This code handles minecart movement and speed capping when on a rail.
1378 */
1379 protected void moveMinecartOnRail(int i, int j, int k)
1380 {
1381 int id = worldObj.getBlockId(i, j, k);
1382 if (!BlockRail.isRailBlock(id))
1383 {
1384 return;
1385 }
1386 float railMaxSpeed = ((BlockRail)Block.blocksList[id]).getRailMaxSpeed(worldObj, this, i, j, k);
1387
1388 double maxSpeed = Math.min(railMaxSpeed, getMaxSpeedRail());
1389 double mX = motionX;
1390 double mZ = motionZ;
1391 if(riddenByEntity != null)
1392 {
1393 mX *= 0.75D;
1394 mZ *= 0.75D;
1395 }
1396 if(mX < -maxSpeed) mX = -maxSpeed;
1397 if(mX > maxSpeed) mX = maxSpeed;
1398 if(mZ < -maxSpeed) mZ = -maxSpeed;
1399 if(mZ > maxSpeed) mZ = maxSpeed;
1400 moveEntity(mX, 0.0D, mZ);
1401 }
1402
1403 /**
1404 * Moved to allow overrides.
1405 * This code handles minecart movement and speed capping when not on a rail.
1406 */
1407 protected void moveMinecartOffRail(int i, int j, int k)
1408 {
1409 double d2 = getMaxSpeedGround();
1410 if(!onGround)
1411 {
1412 d2 = getMaxSpeedAirLateral();
1413 }
1414 if(motionX < -d2) motionX = -d2;
1415 if(motionX > d2) motionX = d2;
1416 if(motionZ < -d2) motionZ = -d2;
1417 if(motionZ > d2) motionZ = d2;
1418 double moveY = motionY;
1419 if(getMaxSpeedAirVertical() > 0 && motionY > getMaxSpeedAirVertical())
1420 {
1421 moveY = getMaxSpeedAirVertical();
1422 if(Math.abs(motionX) < 0.3f && Math.abs(motionZ) < 0.3f)
1423 {
1424 moveY = 0.15f;
1425 motionY = moveY;
1426 }
1427 }
1428 if(onGround)
1429 {
1430 motionX *= 0.5D;
1431 motionY *= 0.5D;
1432 motionZ *= 0.5D;
1433 }
1434 moveEntity(motionX, moveY, motionZ);
1435 if(!onGround)
1436 {
1437 motionX *= getDragAir();
1438 motionY *= getDragAir();
1439 motionZ *= getDragAir();
1440 }
1441 }
1442
1443 /**
1444 * Moved to allow overrides.
1445 * This code applies fuel consumption.
1446 */
1447 protected void updateFuel()
1448 {
1449 if (fuel > 0) fuel--;
1450 if (fuel <= 0) pushX = pushZ = 0.0D;
1451 setMinecartPowered(fuel > 0);
1452 }
1453
1454 /**
1455 * Moved to allow overrides, This code handle slopes affecting velocity.
1456 * @param metadata The blocks position metadata
1457 */
1458 protected void adjustSlopeVelocities(int metadata)
1459 {
1460 double acceleration = 0.0078125D;
1461 if (metadata == 2)
1462 {
1463 motionX -= acceleration;
1464 }
1465 else if (metadata == 3)
1466 {
1467 motionX += acceleration;
1468 }
1469 else if (metadata == 4)
1470 {
1471 motionZ += acceleration;
1472 }
1473 else if (metadata == 5)
1474 {
1475 motionZ -= acceleration;
1476 }
1477 }
1478
1479 /**
1480 * Getters/setters for physics variables
1481 */
1482
1483 /**
1484 * Returns the carts max speed.
1485 * Carts going faster than 1.1 cause issues with chunk loading.
1486 * Carts cant traverse slopes or corners at greater than 0.5 - 0.6.
1487 * This value is compared with the rails max speed to determine
1488 * the carts current max speed. A normal rails max speed is 0.4.
1489 * @return Carts max speed.
1490 */
1491 public float getMaxSpeedRail()
1492 {
1493 return maxSpeedRail;
1494 }
1495
1496 public void setMaxSpeedRail(float value)
1497 {
1498 maxSpeedRail = value;
1499 }
1500
1501 public float getMaxSpeedGround()
1502 {
1503 return maxSpeedGround;
1504 }
1505
1506 public void setMaxSpeedGround(float value)
1507 {
1508 maxSpeedGround = value;
1509 }
1510
1511 public float getMaxSpeedAirLateral()
1512 {
1513 return maxSpeedAirLateral;
1514 }
1515
1516 public void setMaxSpeedAirLateral(float value)
1517 {
1518 maxSpeedAirLateral = value;
1519 }
1520
1521 public float getMaxSpeedAirVertical()
1522 {
1523 return maxSpeedAirVertical;
1524 }
1525
1526 public void setMaxSpeedAirVertical(float value)
1527 {
1528 maxSpeedAirVertical = value;
1529 }
1530
1531 public double getDragAir()
1532 {
1533 return dragAir;
1534 }
1535
1536 public void setDragAir(double value)
1537 {
1538 dragAir = value;
1539 }
1540 }