001package net.minecraft.entity.item;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import java.util.List;
006import net.minecraft.block.Block;
007import net.minecraft.block.material.Material;
008import net.minecraft.entity.Entity;
009import net.minecraft.entity.player.EntityPlayer;
010import net.minecraft.item.Item;
011import net.minecraft.nbt.NBTTagCompound;
012import net.minecraft.util.AxisAlignedBB;
013import net.minecraft.util.DamageSource;
014import net.minecraft.util.MathHelper;
015import net.minecraft.world.World;
016
017public 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}