001package net.minecraft.entity.item; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.List; 006import net.minecraft.block.Block; 007import net.minecraft.block.BlockRailBase; 008import net.minecraft.entity.Entity; 009import net.minecraft.entity.EntityLiving; 010import net.minecraft.entity.ai.EntityMinecartMobSpawner; 011import net.minecraft.entity.monster.EntityIronGolem; 012import net.minecraft.entity.player.EntityPlayer; 013import net.minecraft.item.Item; 014import net.minecraft.item.ItemStack; 015import net.minecraft.nbt.NBTTagCompound; 016import net.minecraft.server.MinecraftServer; 017import net.minecraft.server.gui.IUpdatePlayerListBox; 018import net.minecraft.util.AxisAlignedBB; 019import net.minecraft.util.DamageSource; 020import net.minecraft.util.MathHelper; 021import net.minecraft.util.Vec3; 022import net.minecraft.world.World; 023import net.minecraft.world.WorldServer; 024import net.minecraftforge.common.IMinecartCollisionHandler; 025import net.minecraftforge.common.MinecraftForge; 026import net.minecraftforge.event.entity.minecart.MinecartCollisionEvent; 027import net.minecraftforge.event.entity.minecart.MinecartUpdateEvent; 028 029public abstract class EntityMinecart extends Entity 030{ 031 protected boolean isInReverse; 032 protected final IUpdatePlayerListBox field_82344_g; 033 protected String entityName; 034 035 /** Minecart rotational logic matrix */ 036 protected static final int[][][] matrix = 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}}}; 037 038 /** appears to be the progress of the turn */ 039 protected int turnProgress; 040 protected double minecartX; 041 protected double minecartY; 042 protected double minecartZ; 043 protected double minecartYaw; 044 protected double minecartPitch; 045 @SideOnly(Side.CLIENT) 046 protected double velocityX; 047 @SideOnly(Side.CLIENT) 048 protected double velocityY; 049 @SideOnly(Side.CLIENT) 050 protected double velocityZ; 051 052 /* Forge: Minecart Compatibility Layer Integration. */ 053 public static float defaultMaxSpeedAirLateral = 0.4f; 054 public static float defaultMaxSpeedAirVertical = -1f; 055 public static double defaultDragAir = 0.94999998807907104D; 056 protected boolean canUseRail = true; 057 protected boolean canBePushed = true; 058 private static IMinecartCollisionHandler collisionHandler = null; 059 060 /* Instance versions of the above physics properties */ 061 private float currentSpeedRail = getMaxCartSpeedOnRail(); 062 protected float maxSpeedAirLateral = defaultMaxSpeedAirLateral; 063 protected float maxSpeedAirVertical = defaultMaxSpeedAirVertical; 064 protected double dragAir = defaultDragAir; 065 066 public EntityMinecart(World par1World) 067 { 068 super(par1World); 069 this.isInReverse = false; 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 076 /** 077 * Creates a new minecart of the specified type in the specified location in the given world. par0World - world to 078 * create the minecart in, double par1,par3,par5 represent x,y,z respectively. int par7 specifies the type: 1 for 079 * MinecartChest, 2 for MinecartFurnace, 3 for MinecartTNT, 4 for MinecartMobSpawner, 5 for MinecartHopper and 0 for 080 * a standard empty minecart 081 */ 082 public static EntityMinecart createMinecart(World par0World, double par1, double par3, double par5, int par7) 083 { 084 switch (par7) 085 { 086 case 1: 087 return new EntityMinecartChest(par0World, par1, par3, par5); 088 case 2: 089 return new EntityMinecartFurnace(par0World, par1, par3, par5); 090 case 3: 091 return new EntityMinecartTNT(par0World, par1, par3, par5); 092 case 4: 093 return new EntityMinecartMobSpawner(par0World, par1, par3, par5); 094 case 5: 095 return new EntityMinecartHopper(par0World, par1, par3, par5); 096 default: 097 return new EntityMinecartEmpty(par0World, par1, par3, par5); 098 } 099 } 100 101 /** 102 * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to 103 * prevent them from trampling crops 104 */ 105 protected boolean canTriggerWalking() 106 { 107 return false; 108 } 109 110 protected void entityInit() 111 { 112 this.dataWatcher.addObject(17, new Integer(0)); 113 this.dataWatcher.addObject(18, new Integer(1)); 114 this.dataWatcher.addObject(19, new Integer(0)); 115 this.dataWatcher.addObject(20, new Integer(0)); 116 this.dataWatcher.addObject(21, new Integer(6)); 117 this.dataWatcher.addObject(22, Byte.valueOf((byte)0)); 118 } 119 120 /** 121 * Returns a boundingBox used to collide the entity with other entities and blocks. This enables the entity to be 122 * pushable on contact, like boats or minecarts. 123 */ 124 public AxisAlignedBB getCollisionBox(Entity par1Entity) 125 { 126 if (getCollisionHandler() != null) 127 { 128 return getCollisionHandler().getCollisionBox(this, par1Entity); 129 } 130 return par1Entity.canBePushed() ? par1Entity.boundingBox : null; 131 } 132 133 /** 134 * returns the bounding box for this entity 135 */ 136 public AxisAlignedBB getBoundingBox() 137 { 138 if (getCollisionHandler() != null) 139 { 140 return getCollisionHandler().getBoundingBox(this); 141 } 142 return null; 143 } 144 145 /** 146 * Returns true if this entity should push and be pushed by other entities when colliding. 147 */ 148 public boolean canBePushed() 149 { 150 return canBePushed; 151 } 152 153 public EntityMinecart(World par1World, double par2, double par4, double par6) 154 { 155 this(par1World); 156 this.setPosition(par2, par4 + (double)this.yOffset, par6); 157 this.motionX = 0.0D; 158 this.motionY = 0.0D; 159 this.motionZ = 0.0D; 160 this.prevPosX = par2; 161 this.prevPosY = par4; 162 this.prevPosZ = par6; 163 } 164 165 /** 166 * Returns the Y offset from the entity's position for any entity riding this one. 167 */ 168 public double getMountedYOffset() 169 { 170 return (double)this.height * 0.0D - 0.30000001192092896D; 171 } 172 173 /** 174 * Called when the entity is attacked. 175 */ 176 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 177 { 178 if (!this.worldObj.isRemote && !this.isDead) 179 { 180 if (this.isEntityInvulnerable()) 181 { 182 return false; 183 } 184 else 185 { 186 this.setRollingDirection(-this.getRollingDirection()); 187 this.setRollingAmplitude(10); 188 this.setBeenAttacked(); 189 this.setDamage(this.getDamage() + par2 * 10); 190 boolean flag = par1DamageSource.getEntity() instanceof EntityPlayer && ((EntityPlayer)par1DamageSource.getEntity()).capabilities.isCreativeMode; 191 192 if (flag || this.getDamage() > 40) 193 { 194 if (this.riddenByEntity != null) 195 { 196 this.riddenByEntity.mountEntity(this); 197 } 198 199 if (flag && !this.isInvNameLocalized()) 200 { 201 this.setDead(); 202 } 203 else 204 { 205 this.killMinecart(par1DamageSource); 206 } 207 } 208 209 return true; 210 } 211 } 212 else 213 { 214 return true; 215 } 216 } 217 218 public void killMinecart(DamageSource par1DamageSource) 219 { 220 this.setDead(); 221 ItemStack itemstack = new ItemStack(Item.minecartEmpty, 1); 222 223 if (this.entityName != null) 224 { 225 itemstack.setItemName(this.entityName); 226 } 227 228 this.entityDropItem(itemstack, 0.0F); 229 } 230 231 @SideOnly(Side.CLIENT) 232 233 /** 234 * Setups the entity to do the hurt animation. Only used by packets in multiplayer. 235 */ 236 public void performHurtAnimation() 237 { 238 this.setRollingDirection(-this.getRollingDirection()); 239 this.setRollingAmplitude(10); 240 this.setDamage(this.getDamage() + this.getDamage() * 10); 241 } 242 243 /** 244 * Returns true if other Entities should be prevented from moving through this Entity. 245 */ 246 public boolean canBeCollidedWith() 247 { 248 return !this.isDead; 249 } 250 251 /** 252 * Will get destroyed next tick. 253 */ 254 public void setDead() 255 { 256 super.setDead(); 257 258 if (this.field_82344_g != null) 259 { 260 this.field_82344_g.update(); 261 } 262 } 263 264 /** 265 * Called to update the entity's position/logic. 266 */ 267 public void onUpdate() 268 { 269 if (this.field_82344_g != null) 270 { 271 this.field_82344_g.update(); 272 } 273 274 if (this.getRollingAmplitude() > 0) 275 { 276 this.setRollingAmplitude(this.getRollingAmplitude() - 1); 277 } 278 279 if (this.getDamage() > 0) 280 { 281 this.setDamage(this.getDamage() - 1); 282 } 283 284 if (this.posY < -64.0D) 285 { 286 this.kill(); 287 } 288 289 int i; 290 291 if (!this.worldObj.isRemote && this.worldObj instanceof WorldServer) 292 { 293 this.worldObj.theProfiler.startSection("portal"); 294 MinecraftServer minecraftserver = ((WorldServer)this.worldObj).getMinecraftServer(); 295 i = this.getMaxInPortalTime(); 296 297 if (this.inPortal) 298 { 299 if (minecraftserver.getAllowNether()) 300 { 301 if (this.ridingEntity == null && this.timeInPortal++ >= i) 302 { 303 this.timeInPortal = i; 304 this.timeUntilPortal = this.getPortalCooldown(); 305 byte b0; 306 307 if (this.worldObj.provider.dimensionId == -1) 308 { 309 b0 = 0; 310 } 311 else 312 { 313 b0 = -1; 314 } 315 316 this.travelToDimension(b0); 317 } 318 319 this.inPortal = false; 320 } 321 } 322 else 323 { 324 if (this.timeInPortal > 0) 325 { 326 this.timeInPortal -= 4; 327 } 328 329 if (this.timeInPortal < 0) 330 { 331 this.timeInPortal = 0; 332 } 333 } 334 335 if (this.timeUntilPortal > 0) 336 { 337 --this.timeUntilPortal; 338 } 339 340 this.worldObj.theProfiler.endSection(); 341 } 342 343 if (this.worldObj.isRemote) 344 { 345 if (this.turnProgress > 0) 346 { 347 double d0 = this.posX + (this.minecartX - this.posX) / (double)this.turnProgress; 348 double d1 = this.posY + (this.minecartY - this.posY) / (double)this.turnProgress; 349 double d2 = this.posZ + (this.minecartZ - this.posZ) / (double)this.turnProgress; 350 double d3 = MathHelper.wrapAngleTo180_double(this.minecartYaw - (double)this.rotationYaw); 351 this.rotationYaw = (float)((double)this.rotationYaw + d3 / (double)this.turnProgress); 352 this.rotationPitch = (float)((double)this.rotationPitch + (this.minecartPitch - (double)this.rotationPitch) / (double)this.turnProgress); 353 --this.turnProgress; 354 this.setPosition(d0, d1, d2); 355 this.setRotation(this.rotationYaw, this.rotationPitch); 356 } 357 else 358 { 359 this.setPosition(this.posX, this.posY, this.posZ); 360 this.setRotation(this.rotationYaw, this.rotationPitch); 361 } 362 } 363 else 364 { 365 this.prevPosX = this.posX; 366 this.prevPosY = this.posY; 367 this.prevPosZ = this.posZ; 368 this.motionY -= 0.03999999910593033D; 369 int j = MathHelper.floor_double(this.posX); 370 i = MathHelper.floor_double(this.posY); 371 int k = MathHelper.floor_double(this.posZ); 372 373 if (BlockRailBase.isRailBlockAt(this.worldObj, j, i - 1, k)) 374 { 375 --i; 376 } 377 378 double d4 = 0.4D; 379 double d5 = 0.0078125D; 380 int l = this.worldObj.getBlockId(j, i, k); 381 382 if (canUseRail() && BlockRailBase.isRailBlock(l)) 383 { 384 BlockRailBase rail = (BlockRailBase)Block.blocksList[l]; 385 float railMaxSpeed = rail.getRailMaxSpeed(worldObj, this, j, i, k); 386 double maxSpeed = Math.min(railMaxSpeed, getCurrentCartSpeedCapOnRail()); 387 int i1 = rail.getBasicRailMetadata(worldObj, this, j, i, k); 388 this.updateOnTrack(j, i, k, maxSpeed, getSlopeAdjustment(), l, i1); 389 if (l == Block.railActivator.blockID) 390 { 391 this.onActivatorRailPass(j, i, k, (worldObj.getBlockMetadata(j, i, k) & 8) != 0); 392 } 393 } 394 else 395 { 396 this.func_94088_b(onGround ? d4 : getMaxSpeedAirLateral()); 397 } 398 399 this.doBlockCollisions(); 400 this.rotationPitch = 0.0F; 401 double d6 = this.prevPosX - this.posX; 402 double d7 = this.prevPosZ - this.posZ; 403 404 if (d6 * d6 + d7 * d7 > 0.001D) 405 { 406 this.rotationYaw = (float)(Math.atan2(d7, d6) * 180.0D / Math.PI); 407 408 if (this.isInReverse) 409 { 410 this.rotationYaw += 180.0F; 411 } 412 } 413 414 double d8 = (double)MathHelper.wrapAngleTo180_float(this.rotationYaw - this.prevRotationYaw); 415 416 if (d8 < -170.0D || d8 >= 170.0D) 417 { 418 this.rotationYaw += 180.0F; 419 this.isInReverse = !this.isInReverse; 420 } 421 422 this.setRotation(this.rotationYaw, this.rotationPitch); 423 424 AxisAlignedBB box; 425 if (getCollisionHandler() != null) 426 { 427 box = getCollisionHandler().getMinecartCollisionBox(this); 428 } 429 else 430 { 431 box = boundingBox.expand(0.2D, 0.0D, 0.2D); 432 } 433 434 List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, box); 435 436 if (list != null && !list.isEmpty()) 437 { 438 for (int j1 = 0; j1 < list.size(); ++j1) 439 { 440 Entity entity = (Entity)list.get(j1); 441 442 if (entity != this.riddenByEntity && entity.canBePushed() && entity instanceof EntityMinecart) 443 { 444 entity.applyEntityCollision(this); 445 } 446 } 447 } 448 449 if (this.riddenByEntity != null && this.riddenByEntity.isDead) 450 { 451 if (this.riddenByEntity.ridingEntity == this) 452 { 453 this.riddenByEntity.ridingEntity = null; 454 } 455 456 this.riddenByEntity = null; 457 } 458 459 MinecraftForge.EVENT_BUS.post(new MinecartUpdateEvent(this, j, i, k)); 460 } 461 } 462 463 /** 464 * Called every tick the minecart is on an activator rail. 465 */ 466 public void onActivatorRailPass(int par1, int par2, int par3, boolean par4) {} 467 468 protected void func_94088_b(double par1) 469 { 470 if (this.motionX < -par1) 471 { 472 this.motionX = -par1; 473 } 474 475 if (this.motionX > par1) 476 { 477 this.motionX = par1; 478 } 479 480 if (this.motionZ < -par1) 481 { 482 this.motionZ = -par1; 483 } 484 485 if (this.motionZ > par1) 486 { 487 this.motionZ = par1; 488 } 489 490 double moveY = motionY; 491 if(getMaxSpeedAirVertical() > 0 && motionY > getMaxSpeedAirVertical()) 492 { 493 moveY = getMaxSpeedAirVertical(); 494 if(Math.abs(motionX) < 0.3f && Math.abs(motionZ) < 0.3f) 495 { 496 moveY = 0.15f; 497 motionY = moveY; 498 } 499 } 500 501 if (this.onGround) 502 { 503 this.motionX *= 0.5D; 504 this.motionY *= 0.5D; 505 this.motionZ *= 0.5D; 506 } 507 508 this.moveEntity(this.motionX, moveY, this.motionZ); 509 510 if (!this.onGround) 511 { 512 this.motionX *= getDragAir(); 513 this.motionY *= getDragAir(); 514 this.motionZ *= getDragAir(); 515 } 516 } 517 518 protected void updateOnTrack(int par1, int par2, int par3, double par4, double par6, int par8, int par9) 519 { 520 this.fallDistance = 0.0F; 521 Vec3 vec3 = this.func_70489_a(this.posX, this.posY, this.posZ); 522 this.posY = (double)par2; 523 boolean flag = false; 524 boolean flag1 = false; 525 526 if (par8 == Block.railPowered.blockID) 527 { 528 flag = (worldObj.getBlockMetadata(par1, par2, par3) & 8) != 0; 529 flag1 = !flag; 530 } 531 532 if (((BlockRailBase)Block.blocksList[par8]).isPowered()) 533 { 534 par9 &= 7; 535 } 536 537 if (par9 >= 2 && par9 <= 5) 538 { 539 this.posY = (double)(par2 + 1); 540 } 541 542 if (par9 == 2) 543 { 544 this.motionX -= par6; 545 } 546 547 if (par9 == 3) 548 { 549 this.motionX += par6; 550 } 551 552 if (par9 == 4) 553 { 554 this.motionZ += par6; 555 } 556 557 if (par9 == 5) 558 { 559 this.motionZ -= par6; 560 } 561 562 int[][] aint = matrix[par9]; 563 double d2 = (double)(aint[1][0] - aint[0][0]); 564 double d3 = (double)(aint[1][2] - aint[0][2]); 565 double d4 = Math.sqrt(d2 * d2 + d3 * d3); 566 double d5 = this.motionX * d2 + this.motionZ * d3; 567 568 if (d5 < 0.0D) 569 { 570 d2 = -d2; 571 d3 = -d3; 572 } 573 574 double d6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 575 576 if (d6 > 2.0D) 577 { 578 d6 = 2.0D; 579 } 580 581 this.motionX = d6 * d2 / d4; 582 this.motionZ = d6 * d3 / d4; 583 double d7; 584 double d8; 585 586 if (this.riddenByEntity != null) 587 { 588 d7 = this.riddenByEntity.motionX * this.riddenByEntity.motionX + this.riddenByEntity.motionZ * this.riddenByEntity.motionZ; 589 d8 = this.motionX * this.motionX + this.motionZ * this.motionZ; 590 591 if (d7 > 1.0E-4D && d8 < 0.01D) 592 { 593 this.motionX += this.riddenByEntity.motionX * 0.1D; 594 this.motionZ += this.riddenByEntity.motionZ * 0.1D; 595 flag1 = false; 596 } 597 } 598 599 if (flag1 && shouldDoRailFunctions()) 600 { 601 d7 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 602 603 if (d7 < 0.03D) 604 { 605 this.motionX *= 0.0D; 606 this.motionY *= 0.0D; 607 this.motionZ *= 0.0D; 608 } 609 else 610 { 611 this.motionX *= 0.5D; 612 this.motionY *= 0.0D; 613 this.motionZ *= 0.5D; 614 } 615 } 616 617 d7 = 0.0D; 618 d8 = (double)par1 + 0.5D + (double)aint[0][0] * 0.5D; 619 double d9 = (double)par3 + 0.5D + (double)aint[0][2] * 0.5D; 620 double d10 = (double)par1 + 0.5D + (double)aint[1][0] * 0.5D; 621 double d11 = (double)par3 + 0.5D + (double)aint[1][2] * 0.5D; 622 d2 = d10 - d8; 623 d3 = d11 - d9; 624 double d12; 625 double d13; 626 627 if (d2 == 0.0D) 628 { 629 this.posX = (double)par1 + 0.5D; 630 d7 = this.posZ - (double)par3; 631 } 632 else if (d3 == 0.0D) 633 { 634 this.posZ = (double)par3 + 0.5D; 635 d7 = this.posX - (double)par1; 636 } 637 else 638 { 639 d12 = this.posX - d8; 640 d13 = this.posZ - d9; 641 d7 = (d12 * d2 + d13 * d3) * 2.0D; 642 } 643 644 this.posX = d8 + d2 * d7; 645 this.posZ = d9 + d3 * d7; 646 this.setPosition(this.posX, this.posY + (double)this.yOffset, this.posZ); 647 648 moveMinecartOnRail(par1, par2, par3, par4); 649 650 if (aint[0][1] != 0 && MathHelper.floor_double(this.posX) - par1 == aint[0][0] && MathHelper.floor_double(this.posZ) - par3 == aint[0][2]) 651 { 652 this.setPosition(this.posX, this.posY + (double)aint[0][1], this.posZ); 653 } 654 else if (aint[1][1] != 0 && MathHelper.floor_double(this.posX) - par1 == aint[1][0] && MathHelper.floor_double(this.posZ) - par3 == aint[1][2]) 655 { 656 this.setPosition(this.posX, this.posY + (double)aint[1][1], this.posZ); 657 } 658 659 this.applyDrag(); 660 Vec3 vec31 = this.func_70489_a(this.posX, this.posY, this.posZ); 661 662 if (vec31 != null && vec3 != null) 663 { 664 double d14 = (vec3.yCoord - vec31.yCoord) * 0.05D; 665 d6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 666 667 if (d6 > 0.0D) 668 { 669 this.motionX = this.motionX / d6 * (d6 + d14); 670 this.motionZ = this.motionZ / d6 * (d6 + d14); 671 } 672 673 this.setPosition(this.posX, vec31.yCoord, this.posZ); 674 } 675 676 int j1 = MathHelper.floor_double(this.posX); 677 int k1 = MathHelper.floor_double(this.posZ); 678 679 if (j1 != par1 || k1 != par3) 680 { 681 d6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 682 this.motionX = d6 * (double)(j1 - par1); 683 this.motionZ = d6 * (double)(k1 - par3); 684 } 685 686 if(shouldDoRailFunctions()) 687 { 688 ((BlockRailBase)Block.blocksList[par8]).onMinecartPass(worldObj, this, par1, par2, par3); 689 } 690 691 if (flag && shouldDoRailFunctions()) 692 { 693 double d15 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 694 695 if (d15 > 0.01D) 696 { 697 double d16 = 0.06D; 698 this.motionX += this.motionX / d15 * d16; 699 this.motionZ += this.motionZ / d15 * d16; 700 } 701 else if (par9 == 1) 702 { 703 if (this.worldObj.isBlockNormalCube(par1 - 1, par2, par3)) 704 { 705 this.motionX = 0.02D; 706 } 707 else if (this.worldObj.isBlockNormalCube(par1 + 1, par2, par3)) 708 { 709 this.motionX = -0.02D; 710 } 711 } 712 else if (par9 == 0) 713 { 714 if (this.worldObj.isBlockNormalCube(par1, par2, par3 - 1)) 715 { 716 this.motionZ = 0.02D; 717 } 718 else if (this.worldObj.isBlockNormalCube(par1, par2, par3 + 1)) 719 { 720 this.motionZ = -0.02D; 721 } 722 } 723 } 724 } 725 726 protected void applyDrag() 727 { 728 if (this.riddenByEntity != null) 729 { 730 this.motionX *= 0.996999979019165D; 731 this.motionY *= 0.0D; 732 this.motionZ *= 0.996999979019165D; 733 } 734 else 735 { 736 this.motionX *= 0.9599999785423279D; 737 this.motionY *= 0.0D; 738 this.motionZ *= 0.9599999785423279D; 739 } 740 } 741 742 @SideOnly(Side.CLIENT) 743 public Vec3 func_70495_a(double par1, double par3, double par5, double par7) 744 { 745 int i = MathHelper.floor_double(par1); 746 int j = MathHelper.floor_double(par3); 747 int k = MathHelper.floor_double(par5); 748 749 if (BlockRailBase.isRailBlockAt(this.worldObj, i, j - 1, k)) 750 { 751 --j; 752 } 753 754 int l = this.worldObj.getBlockId(i, j, k); 755 756 if (!BlockRailBase.isRailBlock(l)) 757 { 758 return null; 759 } 760 else 761 { 762 int i1 = ((BlockRailBase)Block.blocksList[l]).getBasicRailMetadata(worldObj, this, i, j, k); 763 764 par3 = (double)j; 765 766 if (i1 >= 2 && i1 <= 5) 767 { 768 par3 = (double)(j + 1); 769 } 770 771 int[][] aint = matrix[i1]; 772 double d4 = (double)(aint[1][0] - aint[0][0]); 773 double d5 = (double)(aint[1][2] - aint[0][2]); 774 double d6 = Math.sqrt(d4 * d4 + d5 * d5); 775 d4 /= d6; 776 d5 /= d6; 777 par1 += d4 * par7; 778 par5 += d5 * par7; 779 780 if (aint[0][1] != 0 && MathHelper.floor_double(par1) - i == aint[0][0] && MathHelper.floor_double(par5) - k == aint[0][2]) 781 { 782 par3 += (double)aint[0][1]; 783 } 784 else if (aint[1][1] != 0 && MathHelper.floor_double(par1) - i == aint[1][0] && MathHelper.floor_double(par5) - k == aint[1][2]) 785 { 786 par3 += (double)aint[1][1]; 787 } 788 789 return this.func_70489_a(par1, par3, par5); 790 } 791 } 792 793 public Vec3 func_70489_a(double par1, double par3, double par5) 794 { 795 int i = MathHelper.floor_double(par1); 796 int j = MathHelper.floor_double(par3); 797 int k = MathHelper.floor_double(par5); 798 799 if (BlockRailBase.isRailBlockAt(this.worldObj, i, j - 1, k)) 800 { 801 --j; 802 } 803 804 int l = this.worldObj.getBlockId(i, j, k); 805 806 if (BlockRailBase.isRailBlock(l)) 807 { 808 int i1 = ((BlockRailBase)Block.blocksList[l]).getBasicRailMetadata(worldObj, this, i, j, k); 809 par3 = (double)j; 810 811 if (i1 >= 2 && i1 <= 5) 812 { 813 par3 = (double)(j + 1); 814 } 815 816 int[][] aint = matrix[i1]; 817 double d3 = 0.0D; 818 double d4 = (double)i + 0.5D + (double)aint[0][0] * 0.5D; 819 double d5 = (double)j + 0.5D + (double)aint[0][1] * 0.5D; 820 double d6 = (double)k + 0.5D + (double)aint[0][2] * 0.5D; 821 double d7 = (double)i + 0.5D + (double)aint[1][0] * 0.5D; 822 double d8 = (double)j + 0.5D + (double)aint[1][1] * 0.5D; 823 double d9 = (double)k + 0.5D + (double)aint[1][2] * 0.5D; 824 double d10 = d7 - d4; 825 double d11 = (d8 - d5) * 2.0D; 826 double d12 = d9 - d6; 827 828 if (d10 == 0.0D) 829 { 830 par1 = (double)i + 0.5D; 831 d3 = par5 - (double)k; 832 } 833 else if (d12 == 0.0D) 834 { 835 par5 = (double)k + 0.5D; 836 d3 = par1 - (double)i; 837 } 838 else 839 { 840 double d13 = par1 - d4; 841 double d14 = par5 - d6; 842 d3 = (d13 * d10 + d14 * d12) * 2.0D; 843 } 844 845 par1 = d4 + d10 * d3; 846 par3 = d5 + d11 * d3; 847 par5 = d6 + d12 * d3; 848 849 if (d11 < 0.0D) 850 { 851 ++par3; 852 } 853 854 if (d11 > 0.0D) 855 { 856 par3 += 0.5D; 857 } 858 859 return this.worldObj.getWorldVec3Pool().getVecFromPool(par1, par3, par5); 860 } 861 else 862 { 863 return null; 864 } 865 } 866 867 /** 868 * (abstract) Protected helper method to read subclass entity data from NBT. 869 */ 870 protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 871 { 872 if (par1NBTTagCompound.getBoolean("CustomDisplayTile")) 873 { 874 this.setDisplayTile(par1NBTTagCompound.getInteger("DisplayTile")); 875 this.setDisplayTileData(par1NBTTagCompound.getInteger("DisplayData")); 876 this.setDisplayTileOffset(par1NBTTagCompound.getInteger("DisplayOffset")); 877 } 878 879 if (par1NBTTagCompound.hasKey("CustomName") && par1NBTTagCompound.getString("CustomName").length() > 0) 880 { 881 this.entityName = par1NBTTagCompound.getString("CustomName"); 882 } 883 } 884 885 /** 886 * (abstract) Protected helper method to write subclass entity data to NBT. 887 */ 888 protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 889 { 890 if (this.hasDisplayTile()) 891 { 892 par1NBTTagCompound.setBoolean("CustomDisplayTile", true); 893 par1NBTTagCompound.setInteger("DisplayTile", this.getDisplayTile() == null ? 0 : this.getDisplayTile().blockID); 894 par1NBTTagCompound.setInteger("DisplayData", this.getDisplayTileData()); 895 par1NBTTagCompound.setInteger("DisplayOffset", this.getDisplayTileOffset()); 896 } 897 898 if (this.entityName != null && this.entityName.length() > 0) 899 { 900 par1NBTTagCompound.setString("CustomName", this.entityName); 901 } 902 } 903 904 @SideOnly(Side.CLIENT) 905 public float getShadowSize() 906 { 907 return 0.0F; 908 } 909 910 /** 911 * Applies a velocity to each of the entities pushing them away from each other. Args: entity 912 */ 913 public void applyEntityCollision(Entity par1Entity) 914 { 915 MinecraftForge.EVENT_BUS.post(new MinecartCollisionEvent(this, par1Entity)); 916 if (getCollisionHandler() != null) 917 { 918 getCollisionHandler().onEntityCollision(this, par1Entity); 919 return; 920 } 921 if (!this.worldObj.isRemote) 922 { 923 if (par1Entity != this.riddenByEntity) 924 { 925 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) 926 { 927 par1Entity.mountEntity(this); 928 } 929 930 double d0 = par1Entity.posX - this.posX; 931 double d1 = par1Entity.posZ - this.posZ; 932 double d2 = d0 * d0 + d1 * d1; 933 934 if (d2 >= 9.999999747378752E-5D) 935 { 936 d2 = (double)MathHelper.sqrt_double(d2); 937 d0 /= d2; 938 d1 /= d2; 939 double d3 = 1.0D / d2; 940 941 if (d3 > 1.0D) 942 { 943 d3 = 1.0D; 944 } 945 946 d0 *= d3; 947 d1 *= d3; 948 d0 *= 0.10000000149011612D; 949 d1 *= 0.10000000149011612D; 950 d0 *= (double)(1.0F - this.entityCollisionReduction); 951 d1 *= (double)(1.0F - this.entityCollisionReduction); 952 d0 *= 0.5D; 953 d1 *= 0.5D; 954 955 if (par1Entity instanceof EntityMinecart) 956 { 957 double d4 = par1Entity.posX - this.posX; 958 double d5 = par1Entity.posZ - this.posZ; 959 Vec3 vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(d4, 0.0D, d5).normalize(); 960 Vec3 vec31 = 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(); 961 double d6 = Math.abs(vec3.dotProduct(vec31)); 962 963 if (d6 < 0.800000011920929D) 964 { 965 return; 966 } 967 968 double d7 = par1Entity.motionX + this.motionX; 969 double d8 = par1Entity.motionZ + this.motionZ; 970 971 if (((EntityMinecart)par1Entity).isPoweredCart() && !isPoweredCart()) 972 { 973 this.motionX *= 0.20000000298023224D; 974 this.motionZ *= 0.20000000298023224D; 975 this.addVelocity(par1Entity.motionX - d0, 0.0D, par1Entity.motionZ - d1); 976 par1Entity.motionX *= 0.949999988079071D; 977 par1Entity.motionZ *= 0.949999988079071D; 978 } 979 else if (!((EntityMinecart)par1Entity).isPoweredCart() && isPoweredCart()) 980 { 981 par1Entity.motionX *= 0.20000000298023224D; 982 par1Entity.motionZ *= 0.20000000298023224D; 983 par1Entity.addVelocity(this.motionX + d0, 0.0D, this.motionZ + d1); 984 this.motionX *= 0.949999988079071D; 985 this.motionZ *= 0.949999988079071D; 986 } 987 else 988 { 989 d7 /= 2.0D; 990 d8 /= 2.0D; 991 this.motionX *= 0.20000000298023224D; 992 this.motionZ *= 0.20000000298023224D; 993 this.addVelocity(d7 - d0, 0.0D, d8 - d1); 994 par1Entity.motionX *= 0.20000000298023224D; 995 par1Entity.motionZ *= 0.20000000298023224D; 996 par1Entity.addVelocity(d7 + d0, 0.0D, d8 + d1); 997 } 998 } 999 else 1000 { 1001 this.addVelocity(-d0, 0.0D, -d1); 1002 par1Entity.addVelocity(d0 / 4.0D, 0.0D, d1 / 4.0D); 1003 } 1004 } 1005 } 1006 } 1007 } 1008 1009 @SideOnly(Side.CLIENT) 1010 1011 /** 1012 * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX, 1013 * posY, posZ, yaw, pitch 1014 */ 1015 public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) 1016 { 1017 this.minecartX = par1; 1018 this.minecartY = par3; 1019 this.minecartZ = par5; 1020 this.minecartYaw = (double)par7; 1021 this.minecartPitch = (double)par8; 1022 this.turnProgress = par9 + 2; 1023 this.motionX = this.velocityX; 1024 this.motionY = this.velocityY; 1025 this.motionZ = this.velocityZ; 1026 } 1027 1028 @SideOnly(Side.CLIENT) 1029 1030 /** 1031 * Sets the velocity to the args. Args: x, y, z 1032 */ 1033 public void setVelocity(double par1, double par3, double par5) 1034 { 1035 this.velocityX = this.motionX = par1; 1036 this.velocityY = this.motionY = par3; 1037 this.velocityZ = this.motionZ = par5; 1038 } 1039 1040 /** 1041 * Sets the current amount of damage the minecart has taken. Decreases over time. The cart breaks when this is over 1042 * 40. 1043 */ 1044 public void setDamage(int par1) 1045 { 1046 this.dataWatcher.updateObject(19, Integer.valueOf(par1)); 1047 } 1048 1049 /** 1050 * Gets the current amount of damage the minecart has taken. Decreases over time. The cart breaks when this is over 1051 * 40. 1052 */ 1053 public int getDamage() 1054 { 1055 return this.dataWatcher.getWatchableObjectInt(19); 1056 } 1057 1058 /** 1059 * Sets the rolling amplitude the cart rolls while being attacked. 1060 */ 1061 public void setRollingAmplitude(int par1) 1062 { 1063 this.dataWatcher.updateObject(17, Integer.valueOf(par1)); 1064 } 1065 1066 /** 1067 * Gets the rolling amplitude the cart rolls while being attacked. 1068 */ 1069 public int getRollingAmplitude() 1070 { 1071 return this.dataWatcher.getWatchableObjectInt(17); 1072 } 1073 1074 /** 1075 * Sets the rolling direction the cart rolls while being attacked. Can be 1 or -1. 1076 */ 1077 public void setRollingDirection(int par1) 1078 { 1079 this.dataWatcher.updateObject(18, Integer.valueOf(par1)); 1080 } 1081 1082 /** 1083 * Gets the rolling direction the cart rolls while being attacked. Can be 1 or -1. 1084 */ 1085 public int getRollingDirection() 1086 { 1087 return this.dataWatcher.getWatchableObjectInt(18); 1088 } 1089 1090 public abstract int getMinecartType(); 1091 1092 public Block getDisplayTile() 1093 { 1094 if (!this.hasDisplayTile()) 1095 { 1096 return this.getDefaultDisplayTile(); 1097 } 1098 else 1099 { 1100 int i = this.getDataWatcher().getWatchableObjectInt(20) & 65535; 1101 return i > 0 && i < Block.blocksList.length ? Block.blocksList[i] : null; 1102 } 1103 } 1104 1105 public Block getDefaultDisplayTile() 1106 { 1107 return null; 1108 } 1109 1110 public int getDisplayTileData() 1111 { 1112 return !this.hasDisplayTile() ? this.getDefaultDisplayTileData() : this.getDataWatcher().getWatchableObjectInt(20) >> 16; 1113 } 1114 1115 public int getDefaultDisplayTileData() 1116 { 1117 return 0; 1118 } 1119 1120 public int getDisplayTileOffset() 1121 { 1122 return !this.hasDisplayTile() ? this.getDefaultDisplayTileOffset() : this.getDataWatcher().getWatchableObjectInt(21); 1123 } 1124 1125 public int getDefaultDisplayTileOffset() 1126 { 1127 return 6; 1128 } 1129 1130 public void setDisplayTile(int par1) 1131 { 1132 this.getDataWatcher().updateObject(20, Integer.valueOf(par1 & 65535 | this.getDisplayTileData() << 16)); 1133 this.setHasDisplayTile(true); 1134 } 1135 1136 public void setDisplayTileData(int par1) 1137 { 1138 Block block = this.getDisplayTile(); 1139 int j = block == null ? 0 : block.blockID; 1140 this.getDataWatcher().updateObject(20, Integer.valueOf(j & 65535 | par1 << 16)); 1141 this.setHasDisplayTile(true); 1142 } 1143 1144 public void setDisplayTileOffset(int par1) 1145 { 1146 this.getDataWatcher().updateObject(21, Integer.valueOf(par1)); 1147 this.setHasDisplayTile(true); 1148 } 1149 1150 public boolean hasDisplayTile() 1151 { 1152 return this.getDataWatcher().getWatchableObjectByte(22) == 1; 1153 } 1154 1155 public void setHasDisplayTile(boolean par1) 1156 { 1157 this.getDataWatcher().updateObject(22, Byte.valueOf((byte)(par1 ? 1 : 0))); 1158 } 1159 1160 public void func_96094_a(String par1Str) 1161 { 1162 this.entityName = par1Str; 1163 } 1164 1165 /** 1166 * Gets the username of the entity. 1167 */ 1168 public String getEntityName() 1169 { 1170 return this.entityName != null ? this.entityName : super.getEntityName(); 1171 } 1172 1173 /** 1174 * If this returns false, the inventory name will be used as an unlocalized name, and translated into the player's 1175 * language. Otherwise it will be used directly. 1176 */ 1177 public boolean isInvNameLocalized() 1178 { 1179 return this.entityName != null; 1180 } 1181 1182 public String func_95999_t() 1183 { 1184 return this.entityName; 1185 } 1186 1187 /** 1188 * Moved to allow overrides. 1189 * This code handles minecart movement and speed capping when on a rail. 1190 */ 1191 public void moveMinecartOnRail(int x, int y, int z, double par4){ 1192 double d12 = this.motionX; 1193 double d13 = this.motionZ; 1194 1195 if (this.riddenByEntity != null) 1196 { 1197 d12 *= 0.75D; 1198 d13 *= 0.75D; 1199 } 1200 1201 if (d12 < -par4) 1202 { 1203 d12 = -par4; 1204 } 1205 1206 if (d12 > par4) 1207 { 1208 d12 = par4; 1209 } 1210 1211 if (d13 < -par4) 1212 { 1213 d13 = -par4; 1214 } 1215 1216 if (d13 > par4) 1217 { 1218 d13 = par4; 1219 } 1220 1221 this.moveEntity(d12, 0.0D, d13); 1222 } 1223 1224 /** 1225 * Gets the current global Minecart Collision handler if none 1226 * is registered, returns null 1227 * @return The collision handler or null 1228 */ 1229 public static IMinecartCollisionHandler getCollisionHandler() 1230 { 1231 return collisionHandler; 1232 } 1233 1234 /** 1235 * Sets the global Minecart Collision handler, overwrites any 1236 * that is currently set. 1237 * @param handler The new handler 1238 */ 1239 public static void setCollisionHandler(IMinecartCollisionHandler handler) 1240 { 1241 collisionHandler = handler; 1242 } 1243 1244 /** 1245 * This function returns an ItemStack that represents this cart. 1246 * This should be an ItemStack that can be used by the player to place the cart, 1247 * but is not necessary the item the cart drops when destroyed. 1248 * @return An ItemStack that can be used to place the cart. 1249 */ 1250 public ItemStack getCartItem() 1251 { 1252 if (this instanceof EntityMinecartChest) 1253 { 1254 return new ItemStack(Item.minecartCrate); 1255 } 1256 else if (this instanceof EntityMinecartTNT) 1257 { 1258 return new ItemStack(Item.tntMinecart); 1259 } 1260 else if (this instanceof EntityMinecartFurnace) 1261 { 1262 return new ItemStack(Item.minecartPowered); 1263 } 1264 else if (this instanceof EntityMinecartHopper) 1265 { 1266 return new ItemStack(Item.hopperMinecart); 1267 } 1268 return new ItemStack(Item.minecartEmpty); 1269 } 1270 1271 /** 1272 * Returns true if this cart can currently use rails. 1273 * This function is mainly used to gracefully detach a minecart from a rail. 1274 * @return True if the minecart can use rails. 1275 */ 1276 public boolean canUseRail() 1277 { 1278 return canUseRail; 1279 } 1280 1281 /** 1282 * Set whether the minecart can use rails. 1283 * This function is mainly used to gracefully detach a minecart from a rail. 1284 * @param use Whether the minecart can currently use rails. 1285 */ 1286 public void setCanUseRail(boolean use) 1287 { 1288 canUseRail = use; 1289 } 1290 1291 /** 1292 * Return false if this cart should not call onMinecartPass() and should ignore Powered Rails. 1293 * @return True if this cart should call onMinecartPass(). 1294 */ 1295 public boolean shouldDoRailFunctions() 1296 { 1297 return true; 1298 } 1299 1300 /** 1301 * Returns true if this cart is self propelled. 1302 * @return True if powered. 1303 */ 1304 public boolean isPoweredCart() 1305 { 1306 return getMinecartType()== 2; 1307 } 1308 1309 /** 1310 * Returns true if this cart can be ridden by an Entity. 1311 * @return True if this cart can be ridden. 1312 */ 1313 public boolean canBeRidden() 1314 { 1315 if(this instanceof EntityMinecartEmpty) 1316 { 1317 return true; 1318 } 1319 return false; 1320 } 1321 1322 /** 1323 * Getters/setters for physics variables 1324 */ 1325 1326 /** 1327 * Returns the carts max speed when traveling on rails. Carts going faster 1328 * than 1.1 cause issues with chunk loading. Carts cant traverse slopes or 1329 * corners at greater than 0.5 - 0.6. This value is compared with the rails 1330 * max speed and the carts current speed cap to determine the carts current 1331 * max speed. A normal rail's max speed is 0.4. 1332 * 1333 * @return Carts max speed. 1334 */ 1335 public float getMaxCartSpeedOnRail() 1336 { 1337 return 1.2f; 1338 } 1339 1340 /** 1341 * Returns the current speed cap for the cart when traveling on rails. This 1342 * functions differs from getMaxCartSpeedOnRail() in that it controls 1343 * current movement and cannot be overridden. The value however can never be 1344 * higher than getMaxCartSpeedOnRail(). 1345 * 1346 * @return 1347 */ 1348 public final float getCurrentCartSpeedCapOnRail() 1349 { 1350 return currentSpeedRail; 1351 } 1352 1353 public final void setCurrentCartSpeedCapOnRail(float value) 1354 { 1355 value = Math.min(value, getMaxCartSpeedOnRail()); 1356 currentSpeedRail = value; 1357 } 1358 1359 public float getMaxSpeedAirLateral() 1360 { 1361 return maxSpeedAirLateral; 1362 } 1363 1364 public void setMaxSpeedAirLateral(float value) 1365 { 1366 maxSpeedAirLateral = value; 1367 } 1368 1369 public float getMaxSpeedAirVertical() 1370 { 1371 return maxSpeedAirVertical; 1372 } 1373 1374 public void setMaxSpeedAirVertical(float value) 1375 { 1376 maxSpeedAirVertical = value; 1377 } 1378 1379 public double getDragAir() 1380 { 1381 return dragAir; 1382 } 1383 1384 public void setDragAir(double value) 1385 { 1386 dragAir = value; 1387 } 1388 1389 public double getSlopeAdjustment() 1390 { 1391 return 0.0078125D; 1392 } 1393}