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.material.Material; 008import net.minecraft.entity.Entity; 009import net.minecraft.entity.player.EntityPlayer; 010import net.minecraft.item.Item; 011import net.minecraft.nbt.NBTTagCompound; 012import net.minecraft.util.AxisAlignedBB; 013import net.minecraft.util.DamageSource; 014import net.minecraft.util.MathHelper; 015import net.minecraft.world.World; 016 017public class EntityBoat extends Entity 018{ 019 private boolean field_70279_a; 020 private double field_70276_b; 021 private int boatPosRotationIncrements; 022 private double boatX; 023 private double boatY; 024 private double boatZ; 025 private double boatYaw; 026 private double boatPitch; 027 @SideOnly(Side.CLIENT) 028 private double velocityX; 029 @SideOnly(Side.CLIENT) 030 private double velocityY; 031 @SideOnly(Side.CLIENT) 032 private double velocityZ; 033 034 public EntityBoat(World par1World) 035 { 036 super(par1World); 037 this.field_70279_a = true; 038 this.field_70276_b = 0.07D; 039 this.preventEntitySpawning = true; 040 this.setSize(1.5F, 0.6F); 041 this.yOffset = this.height / 2.0F; 042 } 043 044 /** 045 * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to 046 * prevent them from trampling crops 047 */ 048 protected boolean canTriggerWalking() 049 { 050 return false; 051 } 052 053 protected void entityInit() 054 { 055 this.dataWatcher.addObject(17, new Integer(0)); 056 this.dataWatcher.addObject(18, new Integer(1)); 057 this.dataWatcher.addObject(19, new Integer(0)); 058 } 059 060 /** 061 * Returns a boundingBox used to collide the entity with other entities and blocks. This enables the entity to be 062 * pushable on contact, like boats or minecarts. 063 */ 064 public AxisAlignedBB getCollisionBox(Entity par1Entity) 065 { 066 return par1Entity.boundingBox; 067 } 068 069 /** 070 * returns the bounding box for this entity 071 */ 072 public AxisAlignedBB getBoundingBox() 073 { 074 return this.boundingBox; 075 } 076 077 /** 078 * Returns true if this entity should push and be pushed by other entities when colliding. 079 */ 080 public boolean canBePushed() 081 { 082 return true; 083 } 084 085 public EntityBoat(World par1World, double par2, double par4, double par6) 086 { 087 this(par1World); 088 this.setPosition(par2, par4 + (double)this.yOffset, par6); 089 this.motionX = 0.0D; 090 this.motionY = 0.0D; 091 this.motionZ = 0.0D; 092 this.prevPosX = par2; 093 this.prevPosY = par4; 094 this.prevPosZ = par6; 095 } 096 097 /** 098 * Returns the Y offset from the entity's position for any entity riding this one. 099 */ 100 public double getMountedYOffset() 101 { 102 return (double)this.height * 0.0D - 0.30000001192092896D; 103 } 104 105 /** 106 * Called when the entity is attacked. 107 */ 108 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 109 { 110 if (this.isEntityInvulnerable()) 111 { 112 return false; 113 } 114 else if (!this.worldObj.isRemote && !this.isDead) 115 { 116 this.setForwardDirection(-this.getForwardDirection()); 117 this.setTimeSinceHit(10); 118 this.setDamageTaken(this.getDamageTaken() + par2 * 10); 119 this.setBeenAttacked(); 120 boolean flag = par1DamageSource.getEntity() instanceof EntityPlayer && ((EntityPlayer)par1DamageSource.getEntity()).capabilities.isCreativeMode; 121 122 if (flag || this.getDamageTaken() > 40) 123 { 124 if (this.riddenByEntity != null) 125 { 126 this.riddenByEntity.mountEntity(this); 127 } 128 129 if (!flag) 130 { 131 this.dropItemWithOffset(Item.boat.itemID, 1, 0.0F); 132 } 133 134 this.setDead(); 135 } 136 137 return true; 138 } 139 else 140 { 141 return true; 142 } 143 } 144 145 @SideOnly(Side.CLIENT) 146 147 /** 148 * Setups the entity to do the hurt animation. Only used by packets in multiplayer. 149 */ 150 public void performHurtAnimation() 151 { 152 this.setForwardDirection(-this.getForwardDirection()); 153 this.setTimeSinceHit(10); 154 this.setDamageTaken(this.getDamageTaken() * 11); 155 } 156 157 /** 158 * Returns true if other Entities should be prevented from moving through this Entity. 159 */ 160 public boolean canBeCollidedWith() 161 { 162 return !this.isDead; 163 } 164 165 @SideOnly(Side.CLIENT) 166 167 /** 168 * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX, 169 * posY, posZ, yaw, pitch 170 */ 171 public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) 172 { 173 if (this.field_70279_a) 174 { 175 this.boatPosRotationIncrements = par9 + 5; 176 } 177 else 178 { 179 double d3 = par1 - this.posX; 180 double d4 = par3 - this.posY; 181 double d5 = par5 - this.posZ; 182 double d6 = d3 * d3 + d4 * d4 + d5 * d5; 183 184 if (d6 <= 1.0D) 185 { 186 return; 187 } 188 189 this.boatPosRotationIncrements = 3; 190 } 191 192 this.boatX = par1; 193 this.boatY = par3; 194 this.boatZ = par5; 195 this.boatYaw = (double)par7; 196 this.boatPitch = (double)par8; 197 this.motionX = this.velocityX; 198 this.motionY = this.velocityY; 199 this.motionZ = this.velocityZ; 200 } 201 202 @SideOnly(Side.CLIENT) 203 204 /** 205 * Sets the velocity to the args. Args: x, y, z 206 */ 207 public void setVelocity(double par1, double par3, double par5) 208 { 209 this.velocityX = this.motionX = par1; 210 this.velocityY = this.motionY = par3; 211 this.velocityZ = this.motionZ = par5; 212 } 213 214 /** 215 * Called to update the entity's position/logic. 216 */ 217 public void onUpdate() 218 { 219 super.onUpdate(); 220 221 if (this.getTimeSinceHit() > 0) 222 { 223 this.setTimeSinceHit(this.getTimeSinceHit() - 1); 224 } 225 226 if (this.getDamageTaken() > 0) 227 { 228 this.setDamageTaken(this.getDamageTaken() - 1); 229 } 230 231 this.prevPosX = this.posX; 232 this.prevPosY = this.posY; 233 this.prevPosZ = this.posZ; 234 byte b0 = 5; 235 double d0 = 0.0D; 236 237 for (int i = 0; i < b0; ++i) 238 { 239 double d1 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(i + 0) / (double)b0 - 0.125D; 240 double d2 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(i + 1) / (double)b0 - 0.125D; 241 AxisAlignedBB axisalignedbb = AxisAlignedBB.getAABBPool().getAABB(this.boundingBox.minX, d1, this.boundingBox.minZ, this.boundingBox.maxX, d2, this.boundingBox.maxZ); 242 243 if (this.worldObj.isAABBInMaterial(axisalignedbb, Material.water)) 244 { 245 d0 += 1.0D / (double)b0; 246 } 247 } 248 249 double d3 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 250 double d4; 251 double d5; 252 253 if (d3 > 0.26249999999999996D) 254 { 255 d4 = Math.cos((double)this.rotationYaw * Math.PI / 180.0D); 256 d5 = Math.sin((double)this.rotationYaw * Math.PI / 180.0D); 257 258 for (int j = 0; (double)j < 1.0D + d3 * 60.0D; ++j) 259 { 260 double d6 = (double)(this.rand.nextFloat() * 2.0F - 1.0F); 261 double d7 = (double)(this.rand.nextInt(2) * 2 - 1) * 0.7D; 262 double d8; 263 double d9; 264 265 if (this.rand.nextBoolean()) 266 { 267 d8 = this.posX - d4 * d6 * 0.8D + d5 * d7; 268 d9 = this.posZ - d5 * d6 * 0.8D - d4 * d7; 269 this.worldObj.spawnParticle("splash", d8, this.posY - 0.125D, d9, this.motionX, this.motionY, this.motionZ); 270 } 271 else 272 { 273 d8 = this.posX + d4 + d5 * d6 * 0.7D; 274 d9 = this.posZ + d5 - d4 * d6 * 0.7D; 275 this.worldObj.spawnParticle("splash", d8, this.posY - 0.125D, d9, this.motionX, this.motionY, this.motionZ); 276 } 277 } 278 } 279 280 double d10; 281 double d11; 282 283 if (this.worldObj.isRemote && this.field_70279_a) 284 { 285 if (this.boatPosRotationIncrements > 0) 286 { 287 d4 = this.posX + (this.boatX - this.posX) / (double)this.boatPosRotationIncrements; 288 d5 = this.posY + (this.boatY - this.posY) / (double)this.boatPosRotationIncrements; 289 d11 = this.posZ + (this.boatZ - this.posZ) / (double)this.boatPosRotationIncrements; 290 d10 = MathHelper.wrapAngleTo180_double(this.boatYaw - (double)this.rotationYaw); 291 this.rotationYaw = (float)((double)this.rotationYaw + d10 / (double)this.boatPosRotationIncrements); 292 this.rotationPitch = (float)((double)this.rotationPitch + (this.boatPitch - (double)this.rotationPitch) / (double)this.boatPosRotationIncrements); 293 --this.boatPosRotationIncrements; 294 this.setPosition(d4, d5, d11); 295 this.setRotation(this.rotationYaw, this.rotationPitch); 296 } 297 else 298 { 299 d4 = this.posX + this.motionX; 300 d5 = this.posY + this.motionY; 301 d11 = this.posZ + this.motionZ; 302 this.setPosition(d4, d5, d11); 303 304 if (this.onGround) 305 { 306 this.motionX *= 0.5D; 307 this.motionY *= 0.5D; 308 this.motionZ *= 0.5D; 309 } 310 311 this.motionX *= 0.9900000095367432D; 312 this.motionY *= 0.949999988079071D; 313 this.motionZ *= 0.9900000095367432D; 314 } 315 } 316 else 317 { 318 if (d0 < 1.0D) 319 { 320 d4 = d0 * 2.0D - 1.0D; 321 this.motionY += 0.03999999910593033D * d4; 322 } 323 else 324 { 325 if (this.motionY < 0.0D) 326 { 327 this.motionY /= 2.0D; 328 } 329 330 this.motionY += 0.007000000216066837D; 331 } 332 333 if (this.riddenByEntity != null) 334 { 335 this.motionX += this.riddenByEntity.motionX * this.field_70276_b; 336 this.motionZ += this.riddenByEntity.motionZ * this.field_70276_b; 337 } 338 339 d4 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 340 341 if (d4 > 0.35D) 342 { 343 d5 = 0.35D / d4; 344 this.motionX *= d5; 345 this.motionZ *= d5; 346 d4 = 0.35D; 347 } 348 349 if (d4 > d3 && this.field_70276_b < 0.35D) 350 { 351 this.field_70276_b += (0.35D - this.field_70276_b) / 35.0D; 352 353 if (this.field_70276_b > 0.35D) 354 { 355 this.field_70276_b = 0.35D; 356 } 357 } 358 else 359 { 360 this.field_70276_b -= (this.field_70276_b - 0.07D) / 35.0D; 361 362 if (this.field_70276_b < 0.07D) 363 { 364 this.field_70276_b = 0.07D; 365 } 366 } 367 368 if (this.onGround) 369 { 370 this.motionX *= 0.5D; 371 this.motionY *= 0.5D; 372 this.motionZ *= 0.5D; 373 } 374 375 this.moveEntity(this.motionX, this.motionY, this.motionZ); 376 377 if (this.isCollidedHorizontally && d3 > 0.2D) 378 { 379 if (!this.worldObj.isRemote) 380 { 381 this.setDead(); 382 int k; 383 384 for (k = 0; k < 3; ++k) 385 { 386 this.dropItemWithOffset(Block.planks.blockID, 1, 0.0F); 387 } 388 389 for (k = 0; k < 2; ++k) 390 { 391 this.dropItemWithOffset(Item.stick.itemID, 1, 0.0F); 392 } 393 } 394 } 395 else 396 { 397 this.motionX *= 0.9900000095367432D; 398 this.motionY *= 0.949999988079071D; 399 this.motionZ *= 0.9900000095367432D; 400 } 401 402 this.rotationPitch = 0.0F; 403 d5 = (double)this.rotationYaw; 404 d11 = this.prevPosX - this.posX; 405 d10 = this.prevPosZ - this.posZ; 406 407 if (d11 * d11 + d10 * d10 > 0.001D) 408 { 409 d5 = (double)((float)(Math.atan2(d10, d11) * 180.0D / Math.PI)); 410 } 411 412 double d12 = MathHelper.wrapAngleTo180_double(d5 - (double)this.rotationYaw); 413 414 if (d12 > 20.0D) 415 { 416 d12 = 20.0D; 417 } 418 419 if (d12 < -20.0D) 420 { 421 d12 = -20.0D; 422 } 423 424 this.rotationYaw = (float)((double)this.rotationYaw + d12); 425 this.setRotation(this.rotationYaw, this.rotationPitch); 426 427 if (!this.worldObj.isRemote) 428 { 429 List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D)); 430 int l; 431 432 if (list != null && !list.isEmpty()) 433 { 434 for (l = 0; l < list.size(); ++l) 435 { 436 Entity entity = (Entity)list.get(l); 437 438 if (entity != this.riddenByEntity && entity.canBePushed() && entity instanceof EntityBoat) 439 { 440 entity.applyEntityCollision(this); 441 } 442 } 443 } 444 445 for (l = 0; l < 4; ++l) 446 { 447 int i1 = MathHelper.floor_double(this.posX + ((double)(l % 2) - 0.5D) * 0.8D); 448 int j1 = MathHelper.floor_double(this.posZ + ((double)(l / 2) - 0.5D) * 0.8D); 449 450 for (int k1 = 0; k1 < 2; ++k1) 451 { 452 int l1 = MathHelper.floor_double(this.posY) + k1; 453 int i2 = this.worldObj.getBlockId(i1, l1, j1); 454 455 if (i2 == Block.snow.blockID) 456 { 457 this.worldObj.setBlockToAir(i1, l1, j1); 458 } 459 else if (i2 == Block.waterlily.blockID) 460 { 461 this.worldObj.destroyBlock(i1, l1, j1, true); 462 } 463 } 464 } 465 466 if (this.riddenByEntity != null && this.riddenByEntity.isDead) 467 { 468 this.riddenByEntity = null; 469 } 470 } 471 } 472 } 473 474 public void updateRiderPosition() 475 { 476 if (this.riddenByEntity != null) 477 { 478 double d0 = Math.cos((double)this.rotationYaw * Math.PI / 180.0D) * 0.4D; 479 double d1 = Math.sin((double)this.rotationYaw * Math.PI / 180.0D) * 0.4D; 480 this.riddenByEntity.setPosition(this.posX + d0, this.posY + this.getMountedYOffset() + this.riddenByEntity.getYOffset(), this.posZ + d1); 481 } 482 } 483 484 /** 485 * (abstract) Protected helper method to write subclass entity data to NBT. 486 */ 487 protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) {} 488 489 /** 490 * (abstract) Protected helper method to read subclass entity data from NBT. 491 */ 492 protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) {} 493 494 @SideOnly(Side.CLIENT) 495 public float getShadowSize() 496 { 497 return 0.0F; 498 } 499 500 /** 501 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 502 */ 503 public boolean interact(EntityPlayer par1EntityPlayer) 504 { 505 if (this.riddenByEntity != null && this.riddenByEntity instanceof EntityPlayer && this.riddenByEntity != par1EntityPlayer) 506 { 507 return true; 508 } 509 else 510 { 511 if (!this.worldObj.isRemote) 512 { 513 par1EntityPlayer.mountEntity(this); 514 } 515 516 return true; 517 } 518 } 519 520 /** 521 * Sets the damage taken from the last hit. 522 */ 523 public void setDamageTaken(int par1) 524 { 525 this.dataWatcher.updateObject(19, Integer.valueOf(par1)); 526 } 527 528 /** 529 * Gets the damage taken from the last hit. 530 */ 531 public int getDamageTaken() 532 { 533 return this.dataWatcher.getWatchableObjectInt(19); 534 } 535 536 /** 537 * Sets the time to count down from since the last time entity was hit. 538 */ 539 public void setTimeSinceHit(int par1) 540 { 541 this.dataWatcher.updateObject(17, Integer.valueOf(par1)); 542 } 543 544 /** 545 * Gets the time since the last hit. 546 */ 547 public int getTimeSinceHit() 548 { 549 return this.dataWatcher.getWatchableObjectInt(17); 550 } 551 552 /** 553 * Sets the forward direction of the entity. 554 */ 555 public void setForwardDirection(int par1) 556 { 557 this.dataWatcher.updateObject(18, Integer.valueOf(par1)); 558 } 559 560 /** 561 * Gets the forward direction of the entity. 562 */ 563 public int getForwardDirection() 564 { 565 return this.dataWatcher.getWatchableObjectInt(18); 566 } 567 568 @SideOnly(Side.CLIENT) 569 public void func_70270_d(boolean par1) 570 { 571 this.field_70279_a = par1; 572 } 573}