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