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