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.Iterator; 008 import java.util.List; 009 import java.util.Random; 010 011 public abstract class Entity 012 { 013 private static int nextEntityID = 0; 014 public int entityId; 015 public double renderDistanceWeight; 016 017 /** 018 * Blocks entities from spawning when they do their AABB check to make sure the spot is clear of entities that can 019 * prevent spawning. 020 */ 021 public boolean preventEntitySpawning; 022 023 /** The entity that is riding this entity */ 024 public Entity riddenByEntity; 025 026 /** The entity we are currently riding */ 027 public Entity ridingEntity; 028 029 /** Reference to the World object. */ 030 public World worldObj; 031 public double prevPosX; 032 public double prevPosY; 033 public double prevPosZ; 034 035 /** Entity position X */ 036 public double posX; 037 038 /** Entity position Y */ 039 public double posY; 040 041 /** Entity position Z */ 042 public double posZ; 043 044 /** Entity motion X */ 045 public double motionX; 046 047 /** Entity motion Y */ 048 public double motionY; 049 050 /** Entity motion Z */ 051 public double motionZ; 052 053 /** Entity rotation Yaw */ 054 public float rotationYaw; 055 056 /** Entity rotation Pitch */ 057 public float rotationPitch; 058 public float prevRotationYaw; 059 public float prevRotationPitch; 060 061 /** Axis aligned bounding box. */ 062 public final AxisAlignedBB boundingBox; 063 public boolean onGround; 064 065 /** 066 * True if after a move this entity has collided with something on X- or Z-axis 067 */ 068 public boolean isCollidedHorizontally; 069 070 /** 071 * True if after a move this entity has collided with something on Y-axis 072 */ 073 public boolean isCollidedVertically; 074 075 /** 076 * True if after a move this entity has collided with something either vertically or horizontally 077 */ 078 public boolean isCollided; 079 public boolean velocityChanged; 080 protected boolean isInWeb; 081 public boolean field_70135_K; 082 083 /** 084 * Gets set by setDead, so this must be the flag whether an Entity is dead (inactive may be better term) 085 */ 086 public boolean isDead; 087 public float yOffset; 088 089 /** How wide this entity is considered to be */ 090 public float width; 091 092 /** How high this entity is considered to be */ 093 public float height; 094 095 /** The previous ticks distance walked multiplied by 0.6 */ 096 public float prevDistanceWalkedModified; 097 098 /** The distance walked multiplied by 0.6 */ 099 public float distanceWalkedModified; 100 public float fallDistance; 101 102 /** 103 * The distance that has to be exceeded in order to triger a new step sound and an onEntityWalking event on a block 104 */ 105 private int nextStepDistance; 106 107 /** 108 * The entity's X coordinate at the previous tick, used to calculate position during rendering routines 109 */ 110 public double lastTickPosX; 111 112 /** 113 * The entity's Y coordinate at the previous tick, used to calculate position during rendering routines 114 */ 115 public double lastTickPosY; 116 117 /** 118 * The entity's Z coordinate at the previous tick, used to calculate position during rendering routines 119 */ 120 public double lastTickPosZ; 121 public float ySize; 122 123 /** 124 * How high this entity can step up when running into a block to try to get over it (currently make note the entity 125 * will always step up this amount and not just the amount needed) 126 */ 127 public float stepHeight; 128 129 /** 130 * Whether this entity won't clip with collision or not (make note it won't disable gravity) 131 */ 132 public boolean noClip; 133 134 /** 135 * Reduces the velocity applied by entity collisions by the specified percent. 136 */ 137 public float entityCollisionReduction; 138 protected Random rand; 139 140 /** How many ticks has this entity had ran since being alive */ 141 public int ticksExisted; 142 143 /** 144 * The amount of ticks you have to stand inside of fire before be set on fire 145 */ 146 public int fireResistance; 147 private int fire; 148 149 /** 150 * Whether this entity is currently inside of water (if it handles water movement that is) 151 */ 152 protected boolean inWater; 153 154 /** 155 * Remaining time an entity will be "immune" to further damage after being hurt. 156 */ 157 public int hurtResistantTime; 158 private boolean firstUpdate; 159 @SideOnly(Side.CLIENT) 160 161 /** downloadable location of player's skin */ 162 public String skinUrl; 163 @SideOnly(Side.CLIENT) 164 165 /** downloadable location of player's cloak */ 166 public String cloakUrl; 167 protected boolean isImmuneToFire; 168 protected DataWatcher dataWatcher; 169 private double entityRiderPitchDelta; 170 private double entityRiderYawDelta; 171 172 /** Has this entity been added to the chunk its within */ 173 public boolean addedToChunk; 174 public int chunkCoordX; 175 public int chunkCoordY; 176 public int chunkCoordZ; 177 @SideOnly(Side.CLIENT) 178 public int serverPosX; 179 @SideOnly(Side.CLIENT) 180 public int serverPosY; 181 @SideOnly(Side.CLIENT) 182 public int serverPosZ; 183 184 /** 185 * Render entity even if it is outside the camera frustum. Only true in EntityFish for now. Used in RenderGlobal: 186 * render if ignoreFrustumCheck or in frustum. 187 */ 188 public boolean ignoreFrustumCheck; 189 public boolean isAirBorne; 190 public EnumEntitySize myEntitySize; 191 /** Forge: Used to store custom data for each entity. */ 192 private NBTTagCompound customEntityData; 193 public boolean captureDrops = false; 194 public ArrayList<EntityItem> capturedDrops = new ArrayList<EntityItem>(); 195 196 public Entity(World par1World) 197 { 198 this.entityId = nextEntityID++; 199 this.renderDistanceWeight = 1.0D; 200 this.preventEntitySpawning = false; 201 this.boundingBox = AxisAlignedBB.getBoundingBox(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D); 202 this.onGround = false; 203 this.isCollided = false; 204 this.velocityChanged = false; 205 this.field_70135_K = true; 206 this.isDead = false; 207 this.yOffset = 0.0F; 208 this.width = 0.6F; 209 this.height = 1.8F; 210 this.prevDistanceWalkedModified = 0.0F; 211 this.distanceWalkedModified = 0.0F; 212 this.fallDistance = 0.0F; 213 this.nextStepDistance = 1; 214 this.ySize = 0.0F; 215 this.stepHeight = 0.0F; 216 this.noClip = false; 217 this.entityCollisionReduction = 0.0F; 218 this.rand = new Random(); 219 this.ticksExisted = 0; 220 this.fireResistance = 1; 221 this.fire = 0; 222 this.inWater = false; 223 this.hurtResistantTime = 0; 224 this.firstUpdate = true; 225 this.isImmuneToFire = false; 226 this.dataWatcher = new DataWatcher(); 227 this.addedToChunk = false; 228 this.myEntitySize = EnumEntitySize.SIZE_2; 229 this.worldObj = par1World; 230 this.setPosition(0.0D, 0.0D, 0.0D); 231 this.dataWatcher.addObject(0, Byte.valueOf((byte)0)); 232 this.dataWatcher.addObject(1, Short.valueOf((short)300)); 233 this.entityInit(); 234 } 235 236 protected abstract void entityInit(); 237 238 public DataWatcher getDataWatcher() 239 { 240 return this.dataWatcher; 241 } 242 243 public boolean equals(Object par1Obj) 244 { 245 return par1Obj instanceof Entity ? ((Entity)par1Obj).entityId == this.entityId : false; 246 } 247 248 public int hashCode() 249 { 250 return this.entityId; 251 } 252 253 @SideOnly(Side.CLIENT) 254 255 /** 256 * Keeps moving the entity up so it isn't colliding with blocks and other requirements for this entity to be spawned 257 * (only actually used on players though its also on Entity) 258 */ 259 protected void preparePlayerToSpawn() 260 { 261 if (this.worldObj != null) 262 { 263 while (this.posY > 0.0D) 264 { 265 this.setPosition(this.posX, this.posY, this.posZ); 266 267 if (this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty()) 268 { 269 break; 270 } 271 272 ++this.posY; 273 } 274 275 this.motionX = this.motionY = this.motionZ = 0.0D; 276 this.rotationPitch = 0.0F; 277 } 278 } 279 280 /** 281 * Will get destroyed next tick. 282 */ 283 public void setDead() 284 { 285 this.isDead = true; 286 } 287 288 /** 289 * Sets the width and height of the entity. Args: width, height 290 */ 291 protected void setSize(float par1, float par2) 292 { 293 this.width = par1; 294 this.height = par2; 295 float var3 = par1 % 2.0F; 296 297 if ((double)var3 < 0.375D) 298 { 299 this.myEntitySize = EnumEntitySize.SIZE_1; 300 } 301 else if ((double)var3 < 0.75D) 302 { 303 this.myEntitySize = EnumEntitySize.SIZE_2; 304 } 305 else if ((double)var3 < 1.0D) 306 { 307 this.myEntitySize = EnumEntitySize.SIZE_3; 308 } 309 else if ((double)var3 < 1.375D) 310 { 311 this.myEntitySize = EnumEntitySize.SIZE_4; 312 } 313 else if ((double)var3 < 1.75D) 314 { 315 this.myEntitySize = EnumEntitySize.SIZE_5; 316 } 317 else 318 { 319 this.myEntitySize = EnumEntitySize.SIZE_6; 320 } 321 } 322 323 /** 324 * Sets the rotation of the entity 325 */ 326 protected void setRotation(float par1, float par2) 327 { 328 this.rotationYaw = par1 % 360.0F; 329 this.rotationPitch = par2 % 360.0F; 330 } 331 332 /** 333 * Sets the x,y,z of the entity from the given parameters. Also seems to set up a bounding box. 334 */ 335 public void setPosition(double par1, double par3, double par5) 336 { 337 this.posX = par1; 338 this.posY = par3; 339 this.posZ = par5; 340 float var7 = this.width / 2.0F; 341 float var8 = this.height; 342 this.boundingBox.setBounds(par1 - (double)var7, par3 - (double)this.yOffset + (double)this.ySize, par5 - (double)var7, par1 + (double)var7, par3 - (double)this.yOffset + (double)this.ySize + (double)var8, par5 + (double)var7); 343 } 344 345 @SideOnly(Side.CLIENT) 346 347 /** 348 * Adds par1*0.15 to the entity's yaw, and *subtracts* par2*0.15 from the pitch. Clamps pitch from -90 to 90. Both 349 * arguments in degrees. 350 */ 351 public void setAngles(float par1, float par2) 352 { 353 float var3 = this.rotationPitch; 354 float var4 = this.rotationYaw; 355 this.rotationYaw = (float)((double)this.rotationYaw + (double)par1 * 0.15D); 356 this.rotationPitch = (float)((double)this.rotationPitch - (double)par2 * 0.15D); 357 358 if (this.rotationPitch < -90.0F) 359 { 360 this.rotationPitch = -90.0F; 361 } 362 363 if (this.rotationPitch > 90.0F) 364 { 365 this.rotationPitch = 90.0F; 366 } 367 368 this.prevRotationPitch += this.rotationPitch - var3; 369 this.prevRotationYaw += this.rotationYaw - var4; 370 } 371 372 /** 373 * Called to update the entity's position/logic. 374 */ 375 public void onUpdate() 376 { 377 this.onEntityUpdate(); 378 } 379 380 /** 381 * Gets called every tick from main Entity class 382 */ 383 public void onEntityUpdate() 384 { 385 this.worldObj.theProfiler.startSection("entityBaseTick"); 386 387 if (this.ridingEntity != null && this.ridingEntity.isDead) 388 { 389 this.ridingEntity = null; 390 } 391 392 ++this.ticksExisted; 393 this.prevDistanceWalkedModified = this.distanceWalkedModified; 394 this.prevPosX = this.posX; 395 this.prevPosY = this.posY; 396 this.prevPosZ = this.posZ; 397 this.prevRotationPitch = this.rotationPitch; 398 this.prevRotationYaw = this.rotationYaw; 399 int var3; 400 401 if (this.isSprinting() && !this.isInWater()) 402 { 403 int var1 = MathHelper.floor_double(this.posX); 404 int var2 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset); 405 var3 = MathHelper.floor_double(this.posZ); 406 int var4 = this.worldObj.getBlockId(var1, var2, var3); 407 408 if (var4 > 0) 409 { 410 this.worldObj.spawnParticle("tilecrack_" + var4, this.posX + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, this.boundingBox.minY + 0.1D, this.posZ + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, -this.motionX * 4.0D, 1.5D, -this.motionZ * 4.0D); 411 } 412 } 413 414 if (this.handleWaterMovement()) 415 { 416 if (!this.inWater && !this.firstUpdate) 417 { 418 float var6 = MathHelper.sqrt_double(this.motionX * this.motionX * 0.20000000298023224D + this.motionY * this.motionY + this.motionZ * this.motionZ * 0.20000000298023224D) * 0.2F; 419 420 if (var6 > 1.0F) 421 { 422 var6 = 1.0F; 423 } 424 425 this.worldObj.playSoundAtEntity(this, "random.splash", var6, 1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.4F); 426 float var7 = (float)MathHelper.floor_double(this.boundingBox.minY); 427 float var5; 428 float var8; 429 430 for (var3 = 0; (float)var3 < 1.0F + this.width * 20.0F; ++var3) 431 { 432 var8 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width; 433 var5 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width; 434 this.worldObj.spawnParticle("bubble", this.posX + (double)var8, (double)(var7 + 1.0F), this.posZ + (double)var5, this.motionX, this.motionY - (double)(this.rand.nextFloat() * 0.2F), this.motionZ); 435 } 436 437 for (var3 = 0; (float)var3 < 1.0F + this.width * 20.0F; ++var3) 438 { 439 var8 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width; 440 var5 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width; 441 this.worldObj.spawnParticle("splash", this.posX + (double)var8, (double)(var7 + 1.0F), this.posZ + (double)var5, this.motionX, this.motionY, this.motionZ); 442 } 443 } 444 445 this.fallDistance = 0.0F; 446 this.inWater = true; 447 this.fire = 0; 448 } 449 else 450 { 451 this.inWater = false; 452 } 453 454 if (this.worldObj.isRemote) 455 { 456 this.fire = 0; 457 } 458 else if (this.fire > 0) 459 { 460 if (this.isImmuneToFire) 461 { 462 this.fire -= 4; 463 464 if (this.fire < 0) 465 { 466 this.fire = 0; 467 } 468 } 469 else 470 { 471 if (this.fire % 20 == 0) 472 { 473 this.attackEntityFrom(DamageSource.onFire, 1); 474 } 475 476 --this.fire; 477 } 478 } 479 480 if (this.handleLavaMovement()) 481 { 482 this.setOnFireFromLava(); 483 this.fallDistance *= 0.5F; 484 } 485 486 if (this.posY < -64.0D) 487 { 488 this.kill(); 489 } 490 491 if (!this.worldObj.isRemote) 492 { 493 this.setFlag(0, this.fire > 0); 494 this.setFlag(2, this.ridingEntity != null); 495 } 496 497 this.firstUpdate = false; 498 this.worldObj.theProfiler.endSection(); 499 } 500 501 /** 502 * Called whenever the entity is walking inside of lava. 503 */ 504 protected void setOnFireFromLava() 505 { 506 if (!this.isImmuneToFire) 507 { 508 this.attackEntityFrom(DamageSource.lava, 4); 509 this.setFire(15); 510 } 511 } 512 513 /** 514 * Sets entity to burn for x amount of seconds, cannot lower amount of existing fire. 515 */ 516 public void setFire(int par1) 517 { 518 int var2 = par1 * 20; 519 520 if (this.fire < var2) 521 { 522 this.fire = var2; 523 } 524 } 525 526 /** 527 * Removes fire from entity. 528 */ 529 public void extinguish() 530 { 531 this.fire = 0; 532 } 533 534 /** 535 * sets the dead flag. Used when you fall off the bottom of the world. 536 */ 537 protected void kill() 538 { 539 this.setDead(); 540 } 541 542 /** 543 * Checks if the offset position from the entity's current position is inside of liquid. Args: x, y, z 544 */ 545 public boolean isOffsetPositionInLiquid(double par1, double par3, double par5) 546 { 547 AxisAlignedBB var7 = this.boundingBox.getOffsetBoundingBox(par1, par3, par5); 548 List var8 = this.worldObj.getCollidingBoundingBoxes(this, var7); 549 return !var8.isEmpty() ? false : !this.worldObj.isAnyLiquid(var7); 550 } 551 552 /** 553 * Tries to moves the entity by the passed in displacement. Args: x, y, z 554 */ 555 public void moveEntity(double par1, double par3, double par5) 556 { 557 if (this.noClip) 558 { 559 this.boundingBox.offset(par1, par3, par5); 560 this.posX = (this.boundingBox.minX + this.boundingBox.maxX) / 2.0D; 561 this.posY = this.boundingBox.minY + (double)this.yOffset - (double)this.ySize; 562 this.posZ = (this.boundingBox.minZ + this.boundingBox.maxZ) / 2.0D; 563 } 564 else 565 { 566 this.worldObj.theProfiler.startSection("move"); 567 this.ySize *= 0.4F; 568 double var7 = this.posX; 569 double var9 = this.posZ; 570 571 if (this.isInWeb) 572 { 573 this.isInWeb = false; 574 par1 *= 0.25D; 575 par3 *= 0.05000000074505806D; 576 par5 *= 0.25D; 577 this.motionX = 0.0D; 578 this.motionY = 0.0D; 579 this.motionZ = 0.0D; 580 } 581 582 double var11 = par1; 583 double var13 = par3; 584 double var15 = par5; 585 AxisAlignedBB var17 = this.boundingBox.copy(); 586 boolean var18 = this.onGround && this.isSneaking() && this instanceof EntityPlayer; 587 588 if (var18) 589 { 590 double var19; 591 592 for (var19 = 0.05D; par1 != 0.0D && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.getOffsetBoundingBox(par1, -1.0D, 0.0D)).isEmpty(); var11 = par1) 593 { 594 if (par1 < var19 && par1 >= -var19) 595 { 596 par1 = 0.0D; 597 } 598 else if (par1 > 0.0D) 599 { 600 par1 -= var19; 601 } 602 else 603 { 604 par1 += var19; 605 } 606 } 607 608 for (; par5 != 0.0D && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.getOffsetBoundingBox(0.0D, -1.0D, par5)).isEmpty(); var15 = par5) 609 { 610 if (par5 < var19 && par5 >= -var19) 611 { 612 par5 = 0.0D; 613 } 614 else if (par5 > 0.0D) 615 { 616 par5 -= var19; 617 } 618 else 619 { 620 par5 += var19; 621 } 622 } 623 624 while (par1 != 0.0D && par5 != 0.0D && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.getOffsetBoundingBox(par1, -1.0D, par5)).isEmpty()) 625 { 626 if (par1 < var19 && par1 >= -var19) 627 { 628 par1 = 0.0D; 629 } 630 else if (par1 > 0.0D) 631 { 632 par1 -= var19; 633 } 634 else 635 { 636 par1 += var19; 637 } 638 639 if (par5 < var19 && par5 >= -var19) 640 { 641 par5 = 0.0D; 642 } 643 else if (par5 > 0.0D) 644 { 645 par5 -= var19; 646 } 647 else 648 { 649 par5 += var19; 650 } 651 652 var11 = par1; 653 var15 = par5; 654 } 655 } 656 657 List var30 = this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.addCoord(par1, par3, par5)); 658 AxisAlignedBB var21; 659 660 for (Iterator var20 = var30.iterator(); var20.hasNext(); par3 = var21.calculateYOffset(this.boundingBox, par3)) 661 { 662 var21 = (AxisAlignedBB)var20.next(); 663 } 664 665 this.boundingBox.offset(0.0D, par3, 0.0D); 666 667 if (!this.field_70135_K && var13 != par3) 668 { 669 par5 = 0.0D; 670 par3 = 0.0D; 671 par1 = 0.0D; 672 } 673 674 boolean var31 = this.onGround || var13 != par3 && var13 < 0.0D; 675 AxisAlignedBB var22; 676 Iterator var32; 677 678 for (var32 = var30.iterator(); var32.hasNext(); par1 = var22.calculateXOffset(this.boundingBox, par1)) 679 { 680 var22 = (AxisAlignedBB)var32.next(); 681 } 682 683 this.boundingBox.offset(par1, 0.0D, 0.0D); 684 685 if (!this.field_70135_K && var11 != par1) 686 { 687 par5 = 0.0D; 688 par3 = 0.0D; 689 par1 = 0.0D; 690 } 691 692 for (var32 = var30.iterator(); var32.hasNext(); par5 = var22.calculateZOffset(this.boundingBox, par5)) 693 { 694 var22 = (AxisAlignedBB)var32.next(); 695 } 696 697 this.boundingBox.offset(0.0D, 0.0D, par5); 698 699 if (!this.field_70135_K && var15 != par5) 700 { 701 par5 = 0.0D; 702 par3 = 0.0D; 703 par1 = 0.0D; 704 } 705 706 double var23; 707 double var33; 708 709 if (this.stepHeight > 0.0F && var31 && (var18 || this.ySize < 0.05F) && (var11 != par1 || var15 != par5)) 710 { 711 var33 = par1; 712 var23 = par3; 713 double var25 = par5; 714 par1 = var11; 715 par3 = (double)this.stepHeight; 716 par5 = var15; 717 AxisAlignedBB var27 = this.boundingBox.copy(); 718 this.boundingBox.setBB(var17); 719 var30 = this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.addCoord(var11, par3, var15)); 720 AxisAlignedBB var29; 721 Iterator var28; 722 723 for (var28 = var30.iterator(); var28.hasNext(); par3 = var29.calculateYOffset(this.boundingBox, par3)) 724 { 725 var29 = (AxisAlignedBB)var28.next(); 726 } 727 728 this.boundingBox.offset(0.0D, par3, 0.0D); 729 730 if (!this.field_70135_K && var13 != par3) 731 { 732 par5 = 0.0D; 733 par3 = 0.0D; 734 par1 = 0.0D; 735 } 736 737 for (var28 = var30.iterator(); var28.hasNext(); par1 = var29.calculateXOffset(this.boundingBox, par1)) 738 { 739 var29 = (AxisAlignedBB)var28.next(); 740 } 741 742 this.boundingBox.offset(par1, 0.0D, 0.0D); 743 744 if (!this.field_70135_K && var11 != par1) 745 { 746 par5 = 0.0D; 747 par3 = 0.0D; 748 par1 = 0.0D; 749 } 750 751 for (var28 = var30.iterator(); var28.hasNext(); par5 = var29.calculateZOffset(this.boundingBox, par5)) 752 { 753 var29 = (AxisAlignedBB)var28.next(); 754 } 755 756 this.boundingBox.offset(0.0D, 0.0D, par5); 757 758 if (!this.field_70135_K && var15 != par5) 759 { 760 par5 = 0.0D; 761 par3 = 0.0D; 762 par1 = 0.0D; 763 } 764 765 if (!this.field_70135_K && var13 != par3) 766 { 767 par5 = 0.0D; 768 par3 = 0.0D; 769 par1 = 0.0D; 770 } 771 else 772 { 773 par3 = (double)(-this.stepHeight); 774 775 for (var28 = var30.iterator(); var28.hasNext(); par3 = var29.calculateYOffset(this.boundingBox, par3)) 776 { 777 var29 = (AxisAlignedBB)var28.next(); 778 } 779 780 this.boundingBox.offset(0.0D, par3, 0.0D); 781 } 782 783 if (var33 * var33 + var25 * var25 >= par1 * par1 + par5 * par5) 784 { 785 par1 = var33; 786 par3 = var23; 787 par5 = var25; 788 this.boundingBox.setBB(var27); 789 } 790 else 791 { 792 double var37 = this.boundingBox.minY - (double)((int)this.boundingBox.minY); 793 794 if (var37 > 0.0D) 795 { 796 this.ySize = (float)((double)this.ySize + var37 + 0.01D); 797 } 798 } 799 } 800 801 this.worldObj.theProfiler.endSection(); 802 this.worldObj.theProfiler.startSection("rest"); 803 this.posX = (this.boundingBox.minX + this.boundingBox.maxX) / 2.0D; 804 this.posY = this.boundingBox.minY + (double)this.yOffset - (double)this.ySize; 805 this.posZ = (this.boundingBox.minZ + this.boundingBox.maxZ) / 2.0D; 806 this.isCollidedHorizontally = var11 != par1 || var15 != par5; 807 this.isCollidedVertically = var13 != par3; 808 this.onGround = var13 != par3 && var13 < 0.0D; 809 this.isCollided = this.isCollidedHorizontally || this.isCollidedVertically; 810 this.updateFallState(par3, this.onGround); 811 812 if (var11 != par1) 813 { 814 this.motionX = 0.0D; 815 } 816 817 if (var13 != par3) 818 { 819 this.motionY = 0.0D; 820 } 821 822 if (var15 != par5) 823 { 824 this.motionZ = 0.0D; 825 } 826 827 var33 = this.posX - var7; 828 var23 = this.posZ - var9; 829 830 if (this.canTriggerWalking() && !var18 && this.ridingEntity == null) 831 { 832 this.distanceWalkedModified = (float)((double)this.distanceWalkedModified + (double)MathHelper.sqrt_double(var33 * var33 + var23 * var23) * 0.6D); 833 int var34 = MathHelper.floor_double(this.posX); 834 int var26 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset); 835 int var36 = MathHelper.floor_double(this.posZ); 836 int var38 = this.worldObj.getBlockId(var34, var26, var36); 837 838 if (var38 == 0 && this.worldObj.getBlockId(var34, var26 - 1, var36) == Block.fence.blockID) 839 { 840 var38 = this.worldObj.getBlockId(var34, var26 - 1, var36); 841 } 842 843 if (this.distanceWalkedModified > (float)this.nextStepDistance && var38 > 0) 844 { 845 this.nextStepDistance = (int)this.distanceWalkedModified + 1; 846 this.playStepSound(var34, var26, var36, var38); 847 Block.blocksList[var38].onEntityWalking(this.worldObj, var34, var26, var36, this); 848 } 849 } 850 851 this.doBlockCollisions(); 852 boolean var35 = this.isWet(); 853 854 if (this.worldObj.isBoundingBoxBurning(this.boundingBox.contract(0.001D, 0.001D, 0.001D))) 855 { 856 this.dealFireDamage(1); 857 858 if (!var35) 859 { 860 ++this.fire; 861 862 if (this.fire == 0) 863 { 864 this.setFire(8); 865 } 866 } 867 } 868 else if (this.fire <= 0) 869 { 870 this.fire = -this.fireResistance; 871 } 872 873 if (var35 && this.fire > 0) 874 { 875 this.worldObj.playSoundAtEntity(this, "random.fizz", 0.7F, 1.6F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.4F); 876 this.fire = -this.fireResistance; 877 } 878 879 this.worldObj.theProfiler.endSection(); 880 } 881 } 882 883 /** 884 * Checks for block collisions, and calls the associated onBlockCollided method for the collided block. 885 */ 886 protected void doBlockCollisions() 887 { 888 int var1 = MathHelper.floor_double(this.boundingBox.minX + 0.001D); 889 int var2 = MathHelper.floor_double(this.boundingBox.minY + 0.001D); 890 int var3 = MathHelper.floor_double(this.boundingBox.minZ + 0.001D); 891 int var4 = MathHelper.floor_double(this.boundingBox.maxX - 0.001D); 892 int var5 = MathHelper.floor_double(this.boundingBox.maxY - 0.001D); 893 int var6 = MathHelper.floor_double(this.boundingBox.maxZ - 0.001D); 894 895 if (this.worldObj.checkChunksExist(var1, var2, var3, var4, var5, var6)) 896 { 897 for (int var7 = var1; var7 <= var4; ++var7) 898 { 899 for (int var8 = var2; var8 <= var5; ++var8) 900 { 901 for (int var9 = var3; var9 <= var6; ++var9) 902 { 903 int var10 = this.worldObj.getBlockId(var7, var8, var9); 904 905 if (var10 > 0) 906 { 907 Block.blocksList[var10].onEntityCollidedWithBlock(this.worldObj, var7, var8, var9, this); 908 } 909 } 910 } 911 } 912 } 913 } 914 915 /** 916 * Plays step sound at given x, y, z for the entity 917 */ 918 protected void playStepSound(int par1, int par2, int par3, int par4) 919 { 920 StepSound var5 = Block.blocksList[par4].stepSound; 921 922 if (this.worldObj.getBlockId(par1, par2 + 1, par3) == Block.snow.blockID) 923 { 924 var5 = Block.snow.stepSound; 925 this.worldObj.playSoundAtEntity(this, var5.getStepSound(), var5.getVolume() * 0.15F, var5.getPitch()); 926 } 927 else if (!Block.blocksList[par4].blockMaterial.isLiquid()) 928 { 929 this.worldObj.playSoundAtEntity(this, var5.getStepSound(), var5.getVolume() * 0.15F, var5.getPitch()); 930 } 931 } 932 933 /** 934 * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to 935 * prevent them from trampling crops 936 */ 937 protected boolean canTriggerWalking() 938 { 939 return true; 940 } 941 942 /** 943 * Takes in the distance the entity has fallen this tick and whether its on the ground to update the fall distance 944 * and deal fall damage if landing on the ground. Args: distanceFallenThisTick, onGround 945 */ 946 protected void updateFallState(double par1, boolean par3) 947 { 948 if (par3) 949 { 950 if (this.fallDistance > 0.0F) 951 { 952 if (this instanceof EntityLiving) 953 { 954 int var4 = MathHelper.floor_double(this.posX); 955 int var5 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset); 956 int var6 = MathHelper.floor_double(this.posZ); 957 int var7 = this.worldObj.getBlockId(var4, var5, var6); 958 959 if (var7 == 0 && this.worldObj.getBlockId(var4, var5 - 1, var6) == Block.fence.blockID) 960 { 961 var7 = this.worldObj.getBlockId(var4, var5 - 1, var6); 962 } 963 964 if (var7 > 0) 965 { 966 Block.blocksList[var7].onFallenUpon(this.worldObj, var4, var5, var6, this, this.fallDistance); 967 } 968 } 969 970 this.fall(this.fallDistance); 971 this.fallDistance = 0.0F; 972 } 973 } 974 else if (par1 < 0.0D) 975 { 976 this.fallDistance = (float)((double)this.fallDistance - par1); 977 } 978 } 979 980 /** 981 * returns the bounding box for this entity 982 */ 983 public AxisAlignedBB getBoundingBox() 984 { 985 return null; 986 } 987 988 /** 989 * Will deal the specified amount of damage to the entity if the entity isn't immune to fire damage. Args: 990 * amountDamage 991 */ 992 protected void dealFireDamage(int par1) 993 { 994 if (!this.isImmuneToFire) 995 { 996 this.attackEntityFrom(DamageSource.inFire, par1); 997 } 998 } 999 1000 public final boolean isImmuneToFire() 1001 { 1002 return this.isImmuneToFire; 1003 } 1004 1005 /** 1006 * Called when the mob is falling. Calculates and applies fall damage. 1007 */ 1008 protected void fall(float par1) 1009 { 1010 if (this.riddenByEntity != null) 1011 { 1012 this.riddenByEntity.fall(par1); 1013 } 1014 } 1015 1016 /** 1017 * Checks if this entity is either in water or on an open air block in rain (used in wolves). 1018 */ 1019 public boolean isWet() 1020 { 1021 return this.inWater || this.worldObj.canLightningStrikeAt(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)); 1022 } 1023 1024 /** 1025 * Checks if this entity is inside water (if inWater field is true as a result of handleWaterMovement() returning 1026 * true) 1027 */ 1028 public boolean isInWater() 1029 { 1030 return this.inWater; 1031 } 1032 1033 /** 1034 * Returns if this entity is in water and will end up adding the waters velocity to the entity 1035 */ 1036 public boolean handleWaterMovement() 1037 { 1038 return this.worldObj.handleMaterialAcceleration(this.boundingBox.expand(0.0D, -0.4000000059604645D, 0.0D).contract(0.001D, 0.001D, 0.001D), Material.water, this); 1039 } 1040 1041 /** 1042 * Checks if the current block the entity is within of the specified material type 1043 */ 1044 public boolean isInsideOfMaterial(Material par1Material) 1045 { 1046 double var2 = this.posY + (double)this.getEyeHeight(); 1047 int var4 = MathHelper.floor_double(this.posX); 1048 int var5 = MathHelper.floor_float((float)MathHelper.floor_double(var2)); 1049 int var6 = MathHelper.floor_double(this.posZ); 1050 int var7 = this.worldObj.getBlockId(var4, var5, var6); 1051 1052 if (var7 != 0 && Block.blocksList[var7].blockMaterial == par1Material) 1053 { 1054 float var8 = BlockFluid.getFluidHeightPercent(this.worldObj.getBlockMetadata(var4, var5, var6)) - 0.11111111F; 1055 float var9 = (float)(var5 + 1) - var8; 1056 return var2 < (double)var9; 1057 } 1058 else 1059 { 1060 return false; 1061 } 1062 } 1063 1064 public float getEyeHeight() 1065 { 1066 return 0.0F; 1067 } 1068 1069 /** 1070 * Whether or not the current entity is in lava 1071 */ 1072 public boolean handleLavaMovement() 1073 { 1074 return this.worldObj.isMaterialInBB(this.boundingBox.expand(-0.10000000149011612D, -0.4000000059604645D, -0.10000000149011612D), Material.lava); 1075 } 1076 1077 /** 1078 * Used in both water and by flying objects 1079 */ 1080 public void moveFlying(float par1, float par2, float par3) 1081 { 1082 float var4 = par1 * par1 + par2 * par2; 1083 1084 if (var4 >= 1.0E-4F) 1085 { 1086 var4 = MathHelper.sqrt_float(var4); 1087 1088 if (var4 < 1.0F) 1089 { 1090 var4 = 1.0F; 1091 } 1092 1093 var4 = par3 / var4; 1094 par1 *= var4; 1095 par2 *= var4; 1096 float var5 = MathHelper.sin(this.rotationYaw * (float)Math.PI / 180.0F); 1097 float var6 = MathHelper.cos(this.rotationYaw * (float)Math.PI / 180.0F); 1098 this.motionX += (double)(par1 * var6 - par2 * var5); 1099 this.motionZ += (double)(par2 * var6 + par1 * var5); 1100 } 1101 } 1102 1103 @SideOnly(Side.CLIENT) 1104 public int getBrightnessForRender(float par1) 1105 { 1106 int var2 = MathHelper.floor_double(this.posX); 1107 int var3 = MathHelper.floor_double(this.posZ); 1108 1109 if (this.worldObj.blockExists(var2, 0, var3)) 1110 { 1111 double var4 = (this.boundingBox.maxY - this.boundingBox.minY) * 0.66D; 1112 int var6 = MathHelper.floor_double(this.posY - (double)this.yOffset + var4); 1113 return this.worldObj.getLightBrightnessForSkyBlocks(var2, var6, var3, 0); 1114 } 1115 else 1116 { 1117 return 0; 1118 } 1119 } 1120 1121 /** 1122 * Gets how bright this entity is. 1123 */ 1124 public float getBrightness(float par1) 1125 { 1126 int var2 = MathHelper.floor_double(this.posX); 1127 int var3 = MathHelper.floor_double(this.posZ); 1128 1129 if (this.worldObj.blockExists(var2, 0, var3)) 1130 { 1131 double var4 = (this.boundingBox.maxY - this.boundingBox.minY) * 0.66D; 1132 int var6 = MathHelper.floor_double(this.posY - (double)this.yOffset + var4); 1133 return this.worldObj.getLightBrightness(var2, var6, var3); 1134 } 1135 else 1136 { 1137 return 0.0F; 1138 } 1139 } 1140 1141 /** 1142 * Sets the reference to the World object. 1143 */ 1144 public void setWorld(World par1World) 1145 { 1146 this.worldObj = par1World; 1147 } 1148 1149 /** 1150 * Sets the entity's position and rotation. Args: posX, posY, posZ, yaw, pitch 1151 */ 1152 public void setPositionAndRotation(double par1, double par3, double par5, float par7, float par8) 1153 { 1154 this.prevPosX = this.posX = par1; 1155 this.prevPosY = this.posY = par3; 1156 this.prevPosZ = this.posZ = par5; 1157 this.prevRotationYaw = this.rotationYaw = par7; 1158 this.prevRotationPitch = this.rotationPitch = par8; 1159 this.ySize = 0.0F; 1160 double var9 = (double)(this.prevRotationYaw - par7); 1161 1162 if (var9 < -180.0D) 1163 { 1164 this.prevRotationYaw += 360.0F; 1165 } 1166 1167 if (var9 >= 180.0D) 1168 { 1169 this.prevRotationYaw -= 360.0F; 1170 } 1171 1172 this.setPosition(this.posX, this.posY, this.posZ); 1173 this.setRotation(par7, par8); 1174 } 1175 1176 /** 1177 * Sets the location and Yaw/Pitch of an entity in the world 1178 */ 1179 public void setLocationAndAngles(double par1, double par3, double par5, float par7, float par8) 1180 { 1181 this.lastTickPosX = this.prevPosX = this.posX = par1; 1182 this.lastTickPosY = this.prevPosY = this.posY = par3 + (double)this.yOffset; 1183 this.lastTickPosZ = this.prevPosZ = this.posZ = par5; 1184 this.rotationYaw = par7; 1185 this.rotationPitch = par8; 1186 this.setPosition(this.posX, this.posY, this.posZ); 1187 } 1188 1189 /** 1190 * Returns the distance to the entity. Args: entity 1191 */ 1192 public float getDistanceToEntity(Entity par1Entity) 1193 { 1194 float var2 = (float)(this.posX - par1Entity.posX); 1195 float var3 = (float)(this.posY - par1Entity.posY); 1196 float var4 = (float)(this.posZ - par1Entity.posZ); 1197 return MathHelper.sqrt_float(var2 * var2 + var3 * var3 + var4 * var4); 1198 } 1199 1200 /** 1201 * Gets the squared distance to the position. Args: x, y, z 1202 */ 1203 public double getDistanceSq(double par1, double par3, double par5) 1204 { 1205 double var7 = this.posX - par1; 1206 double var9 = this.posY - par3; 1207 double var11 = this.posZ - par5; 1208 return var7 * var7 + var9 * var9 + var11 * var11; 1209 } 1210 1211 /** 1212 * Gets the distance to the position. Args: x, y, z 1213 */ 1214 public double getDistance(double par1, double par3, double par5) 1215 { 1216 double var7 = this.posX - par1; 1217 double var9 = this.posY - par3; 1218 double var11 = this.posZ - par5; 1219 return (double)MathHelper.sqrt_double(var7 * var7 + var9 * var9 + var11 * var11); 1220 } 1221 1222 /** 1223 * Returns the squared distance to the entity. Args: entity 1224 */ 1225 public double getDistanceSqToEntity(Entity par1Entity) 1226 { 1227 double var2 = this.posX - par1Entity.posX; 1228 double var4 = this.posY - par1Entity.posY; 1229 double var6 = this.posZ - par1Entity.posZ; 1230 return var2 * var2 + var4 * var4 + var6 * var6; 1231 } 1232 1233 /** 1234 * Called by a player entity when they collide with an entity 1235 */ 1236 public void onCollideWithPlayer(EntityPlayer par1EntityPlayer) {} 1237 1238 /** 1239 * Applies a velocity to each of the entities pushing them away from each other. Args: entity 1240 */ 1241 public void applyEntityCollision(Entity par1Entity) 1242 { 1243 if (par1Entity.riddenByEntity != this && par1Entity.ridingEntity != this) 1244 { 1245 double var2 = par1Entity.posX - this.posX; 1246 double var4 = par1Entity.posZ - this.posZ; 1247 double var6 = MathHelper.abs_max(var2, var4); 1248 1249 if (var6 >= 0.009999999776482582D) 1250 { 1251 var6 = (double)MathHelper.sqrt_double(var6); 1252 var2 /= var6; 1253 var4 /= var6; 1254 double var8 = 1.0D / var6; 1255 1256 if (var8 > 1.0D) 1257 { 1258 var8 = 1.0D; 1259 } 1260 1261 var2 *= var8; 1262 var4 *= var8; 1263 var2 *= 0.05000000074505806D; 1264 var4 *= 0.05000000074505806D; 1265 var2 *= (double)(1.0F - this.entityCollisionReduction); 1266 var4 *= (double)(1.0F - this.entityCollisionReduction); 1267 this.addVelocity(-var2, 0.0D, -var4); 1268 par1Entity.addVelocity(var2, 0.0D, var4); 1269 } 1270 } 1271 } 1272 1273 /** 1274 * Adds to the current velocity of the entity. Args: x, y, z 1275 */ 1276 public void addVelocity(double par1, double par3, double par5) 1277 { 1278 this.motionX += par1; 1279 this.motionY += par3; 1280 this.motionZ += par5; 1281 this.isAirBorne = true; 1282 } 1283 1284 /** 1285 * Sets that this entity has been attacked. 1286 */ 1287 protected void setBeenAttacked() 1288 { 1289 this.velocityChanged = true; 1290 } 1291 1292 /** 1293 * Called when the entity is attacked. 1294 */ 1295 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 1296 { 1297 this.setBeenAttacked(); 1298 return false; 1299 } 1300 1301 /** 1302 * Returns true if other Entities should be prevented from moving through this Entity. 1303 */ 1304 public boolean canBeCollidedWith() 1305 { 1306 return false; 1307 } 1308 1309 /** 1310 * Returns true if this entity should push and be pushed by other entities when colliding. 1311 */ 1312 public boolean canBePushed() 1313 { 1314 return false; 1315 } 1316 1317 /** 1318 * Adds a value to the player score. Currently not actually used and the entity passed in does nothing. Args: 1319 * entity, scoreToAdd 1320 */ 1321 public void addToPlayerScore(Entity par1Entity, int par2) {} 1322 1323 /** 1324 * adds the ID of this entity to the NBT given 1325 */ 1326 public boolean addEntityID(NBTTagCompound par1NBTTagCompound) 1327 { 1328 String var2 = this.getEntityString(); 1329 1330 if (!this.isDead && var2 != null) 1331 { 1332 par1NBTTagCompound.setString("id", var2); 1333 this.writeToNBT(par1NBTTagCompound); 1334 return true; 1335 } 1336 else 1337 { 1338 return false; 1339 } 1340 } 1341 1342 @SideOnly(Side.CLIENT) 1343 1344 /** 1345 * Checks using a Vec3d to determine if this entity is within range of that vector to be rendered. Args: vec3D 1346 */ 1347 public boolean isInRangeToRenderVec3D(Vec3 par1Vec3) 1348 { 1349 double var2 = this.posX - par1Vec3.xCoord; 1350 double var4 = this.posY - par1Vec3.yCoord; 1351 double var6 = this.posZ - par1Vec3.zCoord; 1352 double var8 = var2 * var2 + var4 * var4 + var6 * var6; 1353 return this.isInRangeToRenderDist(var8); 1354 } 1355 1356 @SideOnly(Side.CLIENT) 1357 1358 /** 1359 * Checks if the entity is in range to render by using the past in distance and comparing it to its average edge 1360 * length * 64 * renderDistanceWeight Args: distance 1361 */ 1362 public boolean isInRangeToRenderDist(double par1) 1363 { 1364 double var3 = this.boundingBox.getAverageEdgeLength(); 1365 var3 *= 64.0D * this.renderDistanceWeight; 1366 return par1 < var3 * var3; 1367 } 1368 1369 @SideOnly(Side.CLIENT) 1370 1371 /** 1372 * Returns the texture's file path as a String. 1373 */ 1374 public String getTexture() 1375 { 1376 return null; 1377 } 1378 1379 /** 1380 * Save the entity to NBT (calls an abstract helper method to write extra data) 1381 */ 1382 public void writeToNBT(NBTTagCompound par1NBTTagCompound) 1383 { 1384 par1NBTTagCompound.setTag("Pos", this.newDoubleNBTList(new double[] {this.posX, this.posY + (double)this.ySize, this.posZ})); 1385 par1NBTTagCompound.setTag("Motion", this.newDoubleNBTList(new double[] {this.motionX, this.motionY, this.motionZ})); 1386 par1NBTTagCompound.setTag("Rotation", this.newFloatNBTList(new float[] {this.rotationYaw, this.rotationPitch})); 1387 par1NBTTagCompound.setFloat("FallDistance", this.fallDistance); 1388 par1NBTTagCompound.setShort("Fire", (short)this.fire); 1389 par1NBTTagCompound.setShort("Air", (short)this.getAir()); 1390 par1NBTTagCompound.setBoolean("OnGround", this.onGround); 1391 if (customEntityData != null) 1392 { 1393 par1NBTTagCompound.setCompoundTag("ForgeData", customEntityData); 1394 } 1395 this.writeEntityToNBT(par1NBTTagCompound); 1396 } 1397 1398 /** 1399 * Reads the entity from NBT (calls an abstract helper method to read specialized data) 1400 */ 1401 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 1402 { 1403 NBTTagList var2 = par1NBTTagCompound.getTagList("Pos"); 1404 NBTTagList var3 = par1NBTTagCompound.getTagList("Motion"); 1405 NBTTagList var4 = par1NBTTagCompound.getTagList("Rotation"); 1406 this.motionX = ((NBTTagDouble)var3.tagAt(0)).data; 1407 this.motionY = ((NBTTagDouble)var3.tagAt(1)).data; 1408 this.motionZ = ((NBTTagDouble)var3.tagAt(2)).data; 1409 1410 if (Math.abs(this.motionX) > 10.0D) 1411 { 1412 this.motionX = 0.0D; 1413 } 1414 1415 if (Math.abs(this.motionY) > 10.0D) 1416 { 1417 this.motionY = 0.0D; 1418 } 1419 1420 if (Math.abs(this.motionZ) > 10.0D) 1421 { 1422 this.motionZ = 0.0D; 1423 } 1424 1425 this.prevPosX = this.lastTickPosX = this.posX = ((NBTTagDouble)var2.tagAt(0)).data; 1426 this.prevPosY = this.lastTickPosY = this.posY = ((NBTTagDouble)var2.tagAt(1)).data; 1427 this.prevPosZ = this.lastTickPosZ = this.posZ = ((NBTTagDouble)var2.tagAt(2)).data; 1428 this.prevRotationYaw = this.rotationYaw = ((NBTTagFloat)var4.tagAt(0)).data; 1429 this.prevRotationPitch = this.rotationPitch = ((NBTTagFloat)var4.tagAt(1)).data; 1430 this.fallDistance = par1NBTTagCompound.getFloat("FallDistance"); 1431 this.fire = par1NBTTagCompound.getShort("Fire"); 1432 this.setAir(par1NBTTagCompound.getShort("Air")); 1433 this.onGround = par1NBTTagCompound.getBoolean("OnGround"); 1434 this.setPosition(this.posX, this.posY, this.posZ); 1435 this.setRotation(this.rotationYaw, this.rotationPitch); 1436 if (par1NBTTagCompound.hasKey("ForgeData")) 1437 { 1438 customEntityData = par1NBTTagCompound.getCompoundTag("ForgeData"); 1439 } 1440 this.readEntityFromNBT(par1NBTTagCompound); 1441 } 1442 1443 /** 1444 * Returns the string that identifies this Entity's class 1445 */ 1446 protected final String getEntityString() 1447 { 1448 return EntityList.getEntityString(this); 1449 } 1450 1451 /** 1452 * (abstract) Protected helper method to read subclass entity data from NBT. 1453 */ 1454 protected abstract void readEntityFromNBT(NBTTagCompound var1); 1455 1456 /** 1457 * (abstract) Protected helper method to write subclass entity data to NBT. 1458 */ 1459 protected abstract void writeEntityToNBT(NBTTagCompound var1); 1460 1461 /** 1462 * creates a NBT list from the array of doubles passed to this function 1463 */ 1464 protected NBTTagList newDoubleNBTList(double ... par1ArrayOfDouble) 1465 { 1466 NBTTagList var2 = new NBTTagList(); 1467 double[] var3 = par1ArrayOfDouble; 1468 int var4 = par1ArrayOfDouble.length; 1469 1470 for (int var5 = 0; var5 < var4; ++var5) 1471 { 1472 double var6 = var3[var5]; 1473 var2.appendTag(new NBTTagDouble((String)null, var6)); 1474 } 1475 1476 return var2; 1477 } 1478 1479 /** 1480 * Returns a new NBTTagList filled with the specified floats 1481 */ 1482 protected NBTTagList newFloatNBTList(float ... par1ArrayOfFloat) 1483 { 1484 NBTTagList var2 = new NBTTagList(); 1485 float[] var3 = par1ArrayOfFloat; 1486 int var4 = par1ArrayOfFloat.length; 1487 1488 for (int var5 = 0; var5 < var4; ++var5) 1489 { 1490 float var6 = var3[var5]; 1491 var2.appendTag(new NBTTagFloat((String)null, var6)); 1492 } 1493 1494 return var2; 1495 } 1496 1497 @SideOnly(Side.CLIENT) 1498 public float getShadowSize() 1499 { 1500 return this.height / 2.0F; 1501 } 1502 1503 /** 1504 * Drops an item stack at the entity's position. Args: itemID, count 1505 */ 1506 public EntityItem dropItem(int par1, int par2) 1507 { 1508 return this.dropItemWithOffset(par1, par2, 0.0F); 1509 } 1510 1511 /** 1512 * Drops an item stack with a specified y offset. Args: itemID, count, yOffset 1513 */ 1514 public EntityItem dropItemWithOffset(int par1, int par2, float par3) 1515 { 1516 return this.entityDropItem(new ItemStack(par1, par2, 0), par3); 1517 } 1518 1519 /** 1520 * Drops an item at the position of the entity. 1521 */ 1522 public EntityItem entityDropItem(ItemStack par1ItemStack, float par2) 1523 { 1524 EntityItem var3 = new EntityItem(this.worldObj, this.posX, this.posY + (double)par2, this.posZ, par1ItemStack); 1525 var3.delayBeforeCanPickup = 10; 1526 if (captureDrops) 1527 { 1528 capturedDrops.add(var3); 1529 } 1530 else 1531 { 1532 this.worldObj.spawnEntityInWorld(var3); 1533 } 1534 return var3; 1535 } 1536 1537 /** 1538 * Checks whether target entity is alive. 1539 */ 1540 public boolean isEntityAlive() 1541 { 1542 return !this.isDead; 1543 } 1544 1545 /** 1546 * Checks if this entity is inside of an opaque block 1547 */ 1548 public boolean isEntityInsideOpaqueBlock() 1549 { 1550 for (int var1 = 0; var1 < 8; ++var1) 1551 { 1552 float var2 = ((float)((var1 >> 0) % 2) - 0.5F) * this.width * 0.8F; 1553 float var3 = ((float)((var1 >> 1) % 2) - 0.5F) * 0.1F; 1554 float var4 = ((float)((var1 >> 2) % 2) - 0.5F) * this.width * 0.8F; 1555 int var5 = MathHelper.floor_double(this.posX + (double)var2); 1556 int var6 = MathHelper.floor_double(this.posY + (double)this.getEyeHeight() + (double)var3); 1557 int var7 = MathHelper.floor_double(this.posZ + (double)var4); 1558 1559 if (this.worldObj.isBlockNormalCube(var5, var6, var7)) 1560 { 1561 return true; 1562 } 1563 } 1564 1565 return false; 1566 } 1567 1568 /** 1569 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 1570 */ 1571 public boolean interact(EntityPlayer par1EntityPlayer) 1572 { 1573 return false; 1574 } 1575 1576 /** 1577 * Returns a boundingBox used to collide the entity with other entities and blocks. This enables the entity to be 1578 * pushable on contact, like boats or minecarts. 1579 */ 1580 public AxisAlignedBB getCollisionBox(Entity par1Entity) 1581 { 1582 return null; 1583 } 1584 1585 /** 1586 * Handles updating while being ridden by an entity 1587 */ 1588 public void updateRidden() 1589 { 1590 if (this.ridingEntity.isDead) 1591 { 1592 this.ridingEntity = null; 1593 } 1594 else 1595 { 1596 this.motionX = 0.0D; 1597 this.motionY = 0.0D; 1598 this.motionZ = 0.0D; 1599 this.onUpdate(); 1600 1601 if (this.ridingEntity != null) 1602 { 1603 this.ridingEntity.updateRiderPosition(); 1604 this.entityRiderYawDelta += (double)(this.ridingEntity.rotationYaw - this.ridingEntity.prevRotationYaw); 1605 1606 for (this.entityRiderPitchDelta += (double)(this.ridingEntity.rotationPitch - this.ridingEntity.prevRotationPitch); this.entityRiderYawDelta >= 180.0D; this.entityRiderYawDelta -= 360.0D) 1607 { 1608 ; 1609 } 1610 1611 while (this.entityRiderYawDelta < -180.0D) 1612 { 1613 this.entityRiderYawDelta += 360.0D; 1614 } 1615 1616 while (this.entityRiderPitchDelta >= 180.0D) 1617 { 1618 this.entityRiderPitchDelta -= 360.0D; 1619 } 1620 1621 while (this.entityRiderPitchDelta < -180.0D) 1622 { 1623 this.entityRiderPitchDelta += 360.0D; 1624 } 1625 1626 double var1 = this.entityRiderYawDelta * 0.5D; 1627 double var3 = this.entityRiderPitchDelta * 0.5D; 1628 float var5 = 10.0F; 1629 1630 if (var1 > (double)var5) 1631 { 1632 var1 = (double)var5; 1633 } 1634 1635 if (var1 < (double)(-var5)) 1636 { 1637 var1 = (double)(-var5); 1638 } 1639 1640 if (var3 > (double)var5) 1641 { 1642 var3 = (double)var5; 1643 } 1644 1645 if (var3 < (double)(-var5)) 1646 { 1647 var3 = (double)(-var5); 1648 } 1649 1650 this.entityRiderYawDelta -= var1; 1651 this.entityRiderPitchDelta -= var3; 1652 this.rotationYaw = (float)((double)this.rotationYaw + var1); 1653 this.rotationPitch = (float)((double)this.rotationPitch + var3); 1654 } 1655 } 1656 } 1657 1658 public void updateRiderPosition() 1659 { 1660 if (!(this.riddenByEntity instanceof EntityPlayer) || !((EntityPlayer)this.riddenByEntity).func_71066_bF()) 1661 { 1662 this.riddenByEntity.lastTickPosX = this.riddenByEntity.posX; 1663 this.riddenByEntity.lastTickPosY = this.riddenByEntity.posY; 1664 this.riddenByEntity.lastTickPosZ = this.riddenByEntity.posZ; 1665 } 1666 1667 this.riddenByEntity.setPosition(this.posX, this.posY + this.getMountedYOffset() + this.riddenByEntity.getYOffset(), this.posZ); 1668 } 1669 1670 /** 1671 * Returns the Y Offset of this entity. 1672 */ 1673 public double getYOffset() 1674 { 1675 return (double)this.yOffset; 1676 } 1677 1678 /** 1679 * Returns the Y offset from the entity's position for any entity riding this one. 1680 */ 1681 public double getMountedYOffset() 1682 { 1683 return (double)this.height * 0.75D; 1684 } 1685 1686 /** 1687 * Called when a player mounts an entity. e.g. mounts a pig, mounts a boat. 1688 */ 1689 public void mountEntity(Entity par1Entity) 1690 { 1691 this.entityRiderPitchDelta = 0.0D; 1692 this.entityRiderYawDelta = 0.0D; 1693 1694 if (par1Entity == null) 1695 { 1696 if (this.ridingEntity != null) 1697 { 1698 this.setLocationAndAngles(this.ridingEntity.posX, this.ridingEntity.boundingBox.minY + (double)this.ridingEntity.height, this.ridingEntity.posZ, this.rotationYaw, this.rotationPitch); 1699 this.ridingEntity.riddenByEntity = null; 1700 } 1701 1702 this.ridingEntity = null; 1703 } 1704 else if (this.ridingEntity == par1Entity) 1705 { 1706 this.unmountEntity(par1Entity); 1707 this.ridingEntity.riddenByEntity = null; 1708 this.ridingEntity = null; 1709 } 1710 else 1711 { 1712 if (this.ridingEntity != null) 1713 { 1714 this.ridingEntity.riddenByEntity = null; 1715 } 1716 1717 if (par1Entity.riddenByEntity != null) 1718 { 1719 par1Entity.riddenByEntity.ridingEntity = null; 1720 } 1721 1722 this.ridingEntity = par1Entity; 1723 par1Entity.riddenByEntity = this; 1724 } 1725 } 1726 1727 /** 1728 * Called when a player unounts an entity. 1729 */ 1730 public void unmountEntity(Entity par1Entity) 1731 { 1732 double var3 = par1Entity.posX; 1733 double var5 = par1Entity.boundingBox.minY + (double)par1Entity.height; 1734 double var7 = par1Entity.posZ; 1735 1736 for (double var9 = -1.5D; var9 < 2.0D; ++var9) 1737 { 1738 for (double var11 = -1.5D; var11 < 2.0D; ++var11) 1739 { 1740 if (var9 != 0.0D || var11 != 0.0D) 1741 { 1742 int var13 = (int)(this.posX + var9); 1743 int var14 = (int)(this.posZ + var11); 1744 AxisAlignedBB var2 = this.boundingBox.getOffsetBoundingBox(var9, 1.0D, var11); 1745 1746 if (this.worldObj.getAllCollidingBoundingBoxes(var2).isEmpty()) 1747 { 1748 if (this.worldObj.doesBlockHaveSolidTopSurface(var13, (int)this.posY, var14)) 1749 { 1750 this.setLocationAndAngles(this.posX + var9, this.posY + 1.0D, this.posZ + var11, this.rotationYaw, this.rotationPitch); 1751 return; 1752 } 1753 1754 if (this.worldObj.doesBlockHaveSolidTopSurface(var13, (int)this.posY - 1, var14) || this.worldObj.getBlockMaterial(var13, (int)this.posY - 1, var14) == Material.water) 1755 { 1756 var3 = this.posX + var9; 1757 var5 = this.posY + 1.0D; 1758 var7 = this.posZ + var11; 1759 } 1760 } 1761 } 1762 } 1763 } 1764 1765 this.setLocationAndAngles(var3, var5, var7, this.rotationYaw, this.rotationPitch); 1766 } 1767 1768 @SideOnly(Side.CLIENT) 1769 1770 /** 1771 * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX, 1772 * posY, posZ, yaw, pitch 1773 */ 1774 public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) 1775 { 1776 this.setPosition(par1, par3, par5); 1777 this.setRotation(par7, par8); 1778 List var10 = this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.contract(0.03125D, 0.0D, 0.03125D)); 1779 1780 if (!var10.isEmpty()) 1781 { 1782 double var11 = 0.0D; 1783 Iterator var13 = var10.iterator(); 1784 1785 while (var13.hasNext()) 1786 { 1787 AxisAlignedBB var14 = (AxisAlignedBB)var13.next(); 1788 1789 if (var14.maxY > var11) 1790 { 1791 var11 = var14.maxY; 1792 } 1793 } 1794 1795 par3 += var11 - this.boundingBox.minY; 1796 this.setPosition(par1, par3, par5); 1797 } 1798 } 1799 1800 public float getCollisionBorderSize() 1801 { 1802 return 0.1F; 1803 } 1804 1805 /** 1806 * returns a (normalized) vector of where this entity is looking 1807 */ 1808 public Vec3 getLookVec() 1809 { 1810 return null; 1811 } 1812 1813 /** 1814 * Called by portal blocks when an entity is within it. 1815 */ 1816 public void setInPortal() {} 1817 1818 @SideOnly(Side.CLIENT) 1819 1820 /** 1821 * Sets the velocity to the args. Args: x, y, z 1822 */ 1823 public void setVelocity(double par1, double par3, double par5) 1824 { 1825 this.motionX = par1; 1826 this.motionY = par3; 1827 this.motionZ = par5; 1828 } 1829 1830 @SideOnly(Side.CLIENT) 1831 public void handleHealthUpdate(byte par1) {} 1832 1833 @SideOnly(Side.CLIENT) 1834 1835 /** 1836 * Setups the entity to do the hurt animation. Only used by packets in multiplayer. 1837 */ 1838 public void performHurtAnimation() {} 1839 1840 @SideOnly(Side.CLIENT) 1841 public void updateCloak() {} 1842 1843 public ItemStack[] getLastActiveItems() 1844 { 1845 return null; 1846 } 1847 1848 @SideOnly(Side.CLIENT) 1849 public void func_70062_b(int par1, ItemStack par2ItemStack) {} 1850 1851 /** 1852 * Returns true if the entity is on fire. Used by render to add the fire effect on rendering. 1853 */ 1854 public boolean isBurning() 1855 { 1856 return this.fire > 0 || this.getFlag(0); 1857 } 1858 1859 @SideOnly(Side.CLIENT) 1860 1861 /** 1862 * Returns true if the entity is riding another entity, used by render to rotate the legs to be in 'sit' position 1863 * for players. 1864 */ 1865 public boolean isRiding() 1866 { 1867 return (this.ridingEntity != null && ridingEntity.shouldRiderSit()) || this.getFlag(2); 1868 } 1869 1870 /** 1871 * Returns if this entity is sneaking. 1872 */ 1873 public boolean isSneaking() 1874 { 1875 return this.getFlag(1); 1876 } 1877 1878 /** 1879 * Sets the sneaking flag. 1880 */ 1881 public void setSneaking(boolean par1) 1882 { 1883 this.setFlag(1, par1); 1884 } 1885 1886 /** 1887 * Get if the Entity is sprinting. 1888 */ 1889 public boolean isSprinting() 1890 { 1891 return this.getFlag(3); 1892 } 1893 1894 /** 1895 * Set sprinting switch for Entity. 1896 */ 1897 public void setSprinting(boolean par1) 1898 { 1899 this.setFlag(3, par1); 1900 } 1901 1902 @SideOnly(Side.CLIENT) 1903 public boolean isEating() 1904 { 1905 return this.getFlag(4); 1906 } 1907 1908 public void setEating(boolean par1) 1909 { 1910 this.setFlag(4, par1); 1911 } 1912 1913 /** 1914 * Returns true if the flag is active for the entity. Known flags: 0) is burning; 1) is sneaking; 2) is riding 1915 * something; 3) is sprinting; 4) is eating 1916 */ 1917 protected boolean getFlag(int par1) 1918 { 1919 return (this.dataWatcher.getWatchableObjectByte(0) & 1 << par1) != 0; 1920 } 1921 1922 /** 1923 * Enable or disable a entity flag, see getEntityFlag to read the know flags. 1924 */ 1925 protected void setFlag(int par1, boolean par2) 1926 { 1927 byte var3 = this.dataWatcher.getWatchableObjectByte(0); 1928 1929 if (par2) 1930 { 1931 this.dataWatcher.updateObject(0, Byte.valueOf((byte)(var3 | 1 << par1))); 1932 } 1933 else 1934 { 1935 this.dataWatcher.updateObject(0, Byte.valueOf((byte)(var3 & ~(1 << par1)))); 1936 } 1937 } 1938 1939 public int getAir() 1940 { 1941 return this.dataWatcher.getWatchableObjectShort(1); 1942 } 1943 1944 public void setAir(int par1) 1945 { 1946 this.dataWatcher.updateObject(1, Short.valueOf((short)par1)); 1947 } 1948 1949 /** 1950 * Called when a lightning bolt hits the entity. 1951 */ 1952 public void onStruckByLightning(EntityLightningBolt par1EntityLightningBolt) 1953 { 1954 this.dealFireDamage(5); 1955 ++this.fire; 1956 1957 if (this.fire == 0) 1958 { 1959 this.setFire(8); 1960 } 1961 } 1962 1963 /** 1964 * This method gets called when the entity kills another one. 1965 */ 1966 public void onKillEntity(EntityLiving par1EntityLiving) {} 1967 1968 /** 1969 * Adds velocity to push the entity out of blocks at the specified x, y, z position Args: x, y, z 1970 */ 1971 protected boolean pushOutOfBlocks(double par1, double par3, double par5) 1972 { 1973 int var7 = MathHelper.floor_double(par1); 1974 int var8 = MathHelper.floor_double(par3); 1975 int var9 = MathHelper.floor_double(par5); 1976 double var10 = par1 - (double)var7; 1977 double var12 = par3 - (double)var8; 1978 double var14 = par5 - (double)var9; 1979 1980 if (this.worldObj.isBlockNormalCube(var7, var8, var9)) 1981 { 1982 boolean var16 = !this.worldObj.isBlockNormalCube(var7 - 1, var8, var9); 1983 boolean var17 = !this.worldObj.isBlockNormalCube(var7 + 1, var8, var9); 1984 boolean var18 = !this.worldObj.isBlockNormalCube(var7, var8 - 1, var9); 1985 boolean var19 = !this.worldObj.isBlockNormalCube(var7, var8 + 1, var9); 1986 boolean var20 = !this.worldObj.isBlockNormalCube(var7, var8, var9 - 1); 1987 boolean var21 = !this.worldObj.isBlockNormalCube(var7, var8, var9 + 1); 1988 byte var22 = -1; 1989 double var23 = 9999.0D; 1990 1991 if (var16 && var10 < var23) 1992 { 1993 var23 = var10; 1994 var22 = 0; 1995 } 1996 1997 if (var17 && 1.0D - var10 < var23) 1998 { 1999 var23 = 1.0D - var10; 2000 var22 = 1; 2001 } 2002 2003 if (var18 && var12 < var23) 2004 { 2005 var23 = var12; 2006 var22 = 2; 2007 } 2008 2009 if (var19 && 1.0D - var12 < var23) 2010 { 2011 var23 = 1.0D - var12; 2012 var22 = 3; 2013 } 2014 2015 if (var20 && var14 < var23) 2016 { 2017 var23 = var14; 2018 var22 = 4; 2019 } 2020 2021 if (var21 && 1.0D - var14 < var23) 2022 { 2023 var23 = 1.0D - var14; 2024 var22 = 5; 2025 } 2026 2027 float var25 = this.rand.nextFloat() * 0.2F + 0.1F; 2028 2029 if (var22 == 0) 2030 { 2031 this.motionX = (double)(-var25); 2032 } 2033 2034 if (var22 == 1) 2035 { 2036 this.motionX = (double)var25; 2037 } 2038 2039 if (var22 == 2) 2040 { 2041 this.motionY = (double)(-var25); 2042 } 2043 2044 if (var22 == 3) 2045 { 2046 this.motionY = (double)var25; 2047 } 2048 2049 if (var22 == 4) 2050 { 2051 this.motionZ = (double)(-var25); 2052 } 2053 2054 if (var22 == 5) 2055 { 2056 this.motionZ = (double)var25; 2057 } 2058 2059 return true; 2060 } 2061 else 2062 { 2063 return false; 2064 } 2065 } 2066 2067 /** 2068 * Sets the Entity inside a web block. 2069 */ 2070 public void setInWeb() 2071 { 2072 this.isInWeb = true; 2073 this.fallDistance = 0.0F; 2074 } 2075 2076 /** 2077 * Gets the username of the entity. 2078 */ 2079 public String getEntityName() 2080 { 2081 String var1 = EntityList.getEntityString(this); 2082 2083 if (var1 == null) 2084 { 2085 var1 = "generic"; 2086 } 2087 2088 return StatCollector.translateToLocal("entity." + var1 + ".name"); 2089 } 2090 2091 /** 2092 * Return the Entity parts making up this Entity (currently only for dragons) 2093 */ 2094 public Entity[] getParts() 2095 { 2096 return null; 2097 } 2098 2099 /** 2100 * Returns true if Entity argument is equal to this Entity 2101 */ 2102 public boolean isEntityEqual(Entity par1Entity) 2103 { 2104 return this == par1Entity; 2105 } 2106 2107 public float func_70079_am() 2108 { 2109 return 0.0F; 2110 } 2111 2112 @SideOnly(Side.CLIENT) 2113 2114 /** 2115 * Sets the head's yaw rotation of the entity. 2116 */ 2117 public void setHeadRotationYaw(float par1) {} 2118 2119 /** 2120 * If returns false, the item will not inflict any damage against entities. 2121 */ 2122 public boolean canAttackWithItem() 2123 { 2124 return true; 2125 } 2126 2127 public String toString() 2128 { 2129 return String.format("%s[\'%s\'/%d, l=\'%s\', x=%.2f, y=%.2f, z=%.2f]", new Object[] {this.getClass().getSimpleName(), this.getEntityName(), Integer.valueOf(this.entityId), this.worldObj == null ? "~NULL~" : this.worldObj.getWorldInfo().getWorldName(), Double.valueOf(this.posX), Double.valueOf(this.posY), Double.valueOf(this.posZ)}); 2130 } 2131 2132 /* ================================== Forge Start =====================================*/ 2133 /** 2134 * Returns a NBTTagCompound that can be used to store custom data for this entity. 2135 * It will be written, and read from disc, so it persists over world saves. 2136 * @return A NBTTagCompound 2137 */ 2138 public NBTTagCompound getEntityData() 2139 { 2140 if (customEntityData == null) 2141 { 2142 customEntityData = new NBTTagCompound(); 2143 } 2144 return customEntityData; 2145 } 2146 2147 /** 2148 * Used in model rendering to determine if the entity riding this entity should be in the 'sitting' position. 2149 * @return false to prevent an entity that is mounted to this entity from displaying the 'sitting' animation. 2150 */ 2151 public boolean shouldRiderSit() 2152 { 2153 return true; 2154 } 2155 2156 /** 2157 * Called when a user uses the creative pick block button on this entity. 2158 * 2159 * @param target The full target the player is looking at 2160 * @return A ItemStack to add to the player's inventory, Null if nothing should be added. 2161 */ 2162 public ItemStack getPickedResult(MovingObjectPosition target) 2163 { 2164 if (this instanceof EntityPainting) 2165 { 2166 return new ItemStack(Item.painting); 2167 } 2168 else if (this instanceof EntityMinecart) 2169 { 2170 return ((EntityMinecart)this).getCartItem(); 2171 } 2172 else if (this instanceof EntityBoat) 2173 { 2174 return new ItemStack(Item.boat); 2175 } 2176 else 2177 { 2178 int id = EntityList.getEntityID(this); 2179 if (id > 0 && EntityList.entityEggs.containsKey(id)) 2180 { 2181 return new ItemStack(Item.monsterPlacer, 1, id); 2182 } 2183 } 2184 return null; 2185 } 2186 }