001 package net.minecraft.entity.item; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import java.util.List; 006 import net.minecraft.block.Block; 007 import net.minecraft.block.material.Material; 008 import net.minecraft.entity.Entity; 009 import net.minecraft.entity.player.EntityPlayer; 010 import net.minecraft.item.Item; 011 import net.minecraft.nbt.NBTTagCompound; 012 import net.minecraft.util.AxisAlignedBB; 013 import net.minecraft.util.DamageSource; 014 import net.minecraft.util.MathHelper; 015 import net.minecraft.world.World; 016 017 public 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 121 if (par1DamageSource.getEntity() instanceof EntityPlayer && ((EntityPlayer)par1DamageSource.getEntity()).capabilities.isCreativeMode) 122 { 123 this.setDamageTaken(100); 124 } 125 126 if (this.getDamageTaken() > 40) 127 { 128 if (this.riddenByEntity != null) 129 { 130 this.riddenByEntity.mountEntity(this); 131 } 132 133 this.dropItemWithOffset(Item.boat.itemID, 1, 0.0F); 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 var10 = par1 - this.posX; 180 double var12 = par3 - this.posY; 181 double var14 = par5 - this.posZ; 182 double var16 = var10 * var10 + var12 * var12 + var14 * var14; 183 184 if (var16 <= 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 var1 = 5; 235 double var2 = 0.0D; 236 237 for (int var4 = 0; var4 < var1; ++var4) 238 { 239 double var5 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(var4 + 0) / (double)var1 - 0.125D; 240 double var7 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(var4 + 1) / (double)var1 - 0.125D; 241 AxisAlignedBB var9 = AxisAlignedBB.getAABBPool().addOrModifyAABBInPool(this.boundingBox.minX, var5, this.boundingBox.minZ, this.boundingBox.maxX, var7, this.boundingBox.maxZ); 242 243 if (this.worldObj.isAABBInMaterial(var9, Material.water)) 244 { 245 var2 += 1.0D / (double)var1; 246 } 247 } 248 249 double var24 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 250 double var6; 251 double var8; 252 253 if (var24 > 0.26249999999999996D) 254 { 255 var6 = Math.cos((double)this.rotationYaw * Math.PI / 180.0D); 256 var8 = Math.sin((double)this.rotationYaw * Math.PI / 180.0D); 257 258 for (int var10 = 0; (double)var10 < 1.0D + var24 * 60.0D; ++var10) 259 { 260 double var11 = (double)(this.rand.nextFloat() * 2.0F - 1.0F); 261 double var13 = (double)(this.rand.nextInt(2) * 2 - 1) * 0.7D; 262 double var15; 263 double var17; 264 265 if (this.rand.nextBoolean()) 266 { 267 var15 = this.posX - var6 * var11 * 0.8D + var8 * var13; 268 var17 = this.posZ - var8 * var11 * 0.8D - var6 * var13; 269 this.worldObj.spawnParticle("splash", var15, this.posY - 0.125D, var17, this.motionX, this.motionY, this.motionZ); 270 } 271 else 272 { 273 var15 = this.posX + var6 + var8 * var11 * 0.7D; 274 var17 = this.posZ + var8 - var6 * var11 * 0.7D; 275 this.worldObj.spawnParticle("splash", var15, this.posY - 0.125D, var17, this.motionX, this.motionY, this.motionZ); 276 } 277 } 278 } 279 280 double var12; 281 double var26; 282 283 if (this.worldObj.isRemote && this.field_70279_a) 284 { 285 if (this.boatPosRotationIncrements > 0) 286 { 287 var6 = this.posX + (this.boatX - this.posX) / (double)this.boatPosRotationIncrements; 288 var8 = this.posY + (this.boatY - this.posY) / (double)this.boatPosRotationIncrements; 289 var26 = this.posZ + (this.boatZ - this.posZ) / (double)this.boatPosRotationIncrements; 290 var12 = MathHelper.wrapAngleTo180_double(this.boatYaw - (double)this.rotationYaw); 291 this.rotationYaw = (float)((double)this.rotationYaw + var12 / (double)this.boatPosRotationIncrements); 292 this.rotationPitch = (float)((double)this.rotationPitch + (this.boatPitch - (double)this.rotationPitch) / (double)this.boatPosRotationIncrements); 293 --this.boatPosRotationIncrements; 294 this.setPosition(var6, var8, var26); 295 this.setRotation(this.rotationYaw, this.rotationPitch); 296 } 297 else 298 { 299 var6 = this.posX + this.motionX; 300 var8 = this.posY + this.motionY; 301 var26 = this.posZ + this.motionZ; 302 this.setPosition(var6, var8, var26); 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 (var2 < 1.0D) 319 { 320 var6 = var2 * 2.0D - 1.0D; 321 this.motionY += 0.03999999910593033D * var6; 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 var6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); 340 341 if (var6 > 0.35D) 342 { 343 var8 = 0.35D / var6; 344 this.motionX *= var8; 345 this.motionZ *= var8; 346 var6 = 0.35D; 347 } 348 349 if (var6 > var24 && 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 && var24 > 0.2D) 378 { 379 if (!this.worldObj.isRemote) 380 { 381 this.setDead(); 382 int var25; 383 384 for (var25 = 0; var25 < 3; ++var25) 385 { 386 this.dropItemWithOffset(Block.planks.blockID, 1, 0.0F); 387 } 388 389 for (var25 = 0; var25 < 2; ++var25) 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 var8 = (double)this.rotationYaw; 404 var26 = this.prevPosX - this.posX; 405 var12 = this.prevPosZ - this.posZ; 406 407 if (var26 * var26 + var12 * var12 > 0.001D) 408 { 409 var8 = (double)((float)(Math.atan2(var12, var26) * 180.0D / Math.PI)); 410 } 411 412 double var14 = MathHelper.wrapAngleTo180_double(var8 - (double)this.rotationYaw); 413 414 if (var14 > 20.0D) 415 { 416 var14 = 20.0D; 417 } 418 419 if (var14 < -20.0D) 420 { 421 var14 = -20.0D; 422 } 423 424 this.rotationYaw = (float)((double)this.rotationYaw + var14); 425 this.setRotation(this.rotationYaw, this.rotationPitch); 426 427 if (!this.worldObj.isRemote) 428 { 429 List var16 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D)); 430 int var27; 431 432 if (var16 != null && !var16.isEmpty()) 433 { 434 for (var27 = 0; var27 < var16.size(); ++var27) 435 { 436 Entity var18 = (Entity)var16.get(var27); 437 438 if (var18 != this.riddenByEntity && var18.canBePushed() && var18 instanceof EntityBoat) 439 { 440 var18.applyEntityCollision(this); 441 } 442 } 443 } 444 445 for (var27 = 0; var27 < 4; ++var27) 446 { 447 int var28 = MathHelper.floor_double(this.posX + ((double)(var27 % 2) - 0.5D) * 0.8D); 448 int var19 = MathHelper.floor_double(this.posZ + ((double)(var27 / 2) - 0.5D) * 0.8D); 449 450 for (int var20 = 0; var20 < 2; ++var20) 451 { 452 int var21 = MathHelper.floor_double(this.posY) + var20; 453 int var22 = this.worldObj.getBlockId(var28, var21, var19); 454 int var23 = this.worldObj.getBlockMetadata(var28, var21, var19); 455 456 if (var22 == Block.snow.blockID) 457 { 458 this.worldObj.setBlockWithNotify(var28, var21, var19, 0); 459 } 460 else if (var22 == Block.waterlily.blockID) 461 { 462 Block.waterlily.dropBlockAsItemWithChance(this.worldObj, var28, var21, var19, var23, 0.3F, 0); 463 this.worldObj.setBlockWithNotify(var28, var21, var19, 0); 464 } 465 } 466 } 467 468 if (this.riddenByEntity != null && this.riddenByEntity.isDead) 469 { 470 this.riddenByEntity = null; 471 } 472 } 473 } 474 } 475 476 public void updateRiderPosition() 477 { 478 if (this.riddenByEntity != null) 479 { 480 double var1 = Math.cos((double)this.rotationYaw * Math.PI / 180.0D) * 0.4D; 481 double var3 = Math.sin((double)this.rotationYaw * Math.PI / 180.0D) * 0.4D; 482 this.riddenByEntity.setPosition(this.posX + var1, this.posY + this.getMountedYOffset() + this.riddenByEntity.getYOffset(), this.posZ + var3); 483 } 484 } 485 486 /** 487 * (abstract) Protected helper method to write subclass entity data to NBT. 488 */ 489 protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) {} 490 491 /** 492 * (abstract) Protected helper method to read subclass entity data from NBT. 493 */ 494 protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) {} 495 496 /** 497 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 498 */ 499 public boolean interact(EntityPlayer par1EntityPlayer) 500 { 501 if (this.riddenByEntity != null && this.riddenByEntity instanceof EntityPlayer && this.riddenByEntity != par1EntityPlayer) 502 { 503 return true; 504 } 505 else 506 { 507 if (!this.worldObj.isRemote) 508 { 509 par1EntityPlayer.mountEntity(this); 510 } 511 512 return true; 513 } 514 } 515 516 /** 517 * Sets the damage taken from the last hit. 518 */ 519 public void setDamageTaken(int par1) 520 { 521 this.dataWatcher.updateObject(19, Integer.valueOf(par1)); 522 } 523 524 @SideOnly(Side.CLIENT) 525 public float getShadowSize() 526 { 527 return 0.0F; 528 } 529 530 /** 531 * Gets the damage taken from the last hit. 532 */ 533 public int getDamageTaken() 534 { 535 return this.dataWatcher.getWatchableObjectInt(19); 536 } 537 538 /** 539 * Sets the time to count down from since the last time entity was hit. 540 */ 541 public void setTimeSinceHit(int par1) 542 { 543 this.dataWatcher.updateObject(17, Integer.valueOf(par1)); 544 } 545 546 /** 547 * Gets the time since the last hit. 548 */ 549 public int getTimeSinceHit() 550 { 551 return this.dataWatcher.getWatchableObjectInt(17); 552 } 553 554 /** 555 * Sets the forward direction of the entity. 556 */ 557 public void setForwardDirection(int par1) 558 { 559 this.dataWatcher.updateObject(18, Integer.valueOf(par1)); 560 } 561 562 /** 563 * Gets the forward direction of the entity. 564 */ 565 public int getForwardDirection() 566 { 567 return this.dataWatcher.getWatchableObjectInt(18); 568 } 569 570 @SideOnly(Side.CLIENT) 571 public void func_70270_d(boolean par1) 572 { 573 this.field_70279_a = par1; 574 } 575 }