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    }