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 }