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    }