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