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 }