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