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 }