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    }