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.worldObj.isRemote && !this.isDead)
102            {
103                this.setForwardDirection(-this.getForwardDirection());
104                this.setTimeSinceHit(10);
105                this.setDamageTaken(this.getDamageTaken() + par2 * 10);
106                this.setBeenAttacked();
107    
108                if (par1DamageSource.getEntity() instanceof EntityPlayer && ((EntityPlayer)par1DamageSource.getEntity()).capabilities.isCreativeMode)
109                {
110                    this.setDamageTaken(100);
111                }
112    
113                if (this.getDamageTaken() > 40)
114                {
115                    if (this.riddenByEntity != null)
116                    {
117                        this.riddenByEntity.mountEntity(this);
118                    }
119    
120                    this.dropItemWithOffset(Item.boat.shiftedIndex, 1, 0.0F);
121                    this.setDead();
122                }
123    
124                return true;
125            }
126            else
127            {
128                return true;
129            }
130        }
131    
132        @SideOnly(Side.CLIENT)
133    
134        /**
135         * Setups the entity to do the hurt animation. Only used by packets in multiplayer.
136         */
137        public void performHurtAnimation()
138        {
139            this.setForwardDirection(-this.getForwardDirection());
140            this.setTimeSinceHit(10);
141            this.setDamageTaken(this.getDamageTaken() * 11);
142        }
143    
144        /**
145         * Returns true if other Entities should be prevented from moving through this Entity.
146         */
147        public boolean canBeCollidedWith()
148        {
149            return !this.isDead;
150        }
151    
152        @SideOnly(Side.CLIENT)
153    
154        /**
155         * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX,
156         * posY, posZ, yaw, pitch
157         */
158        public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
159        {
160            if (this.field_70279_a)
161            {
162                this.boatPosRotationIncrements = par9 + 5;
163            }
164            else
165            {
166                double var10 = par1 - this.posX;
167                double var12 = par3 - this.posY;
168                double var14 = par5 - this.posZ;
169                double var16 = var10 * var10 + var12 * var12 + var14 * var14;
170    
171                if (var16 <= 1.0D)
172                {
173                    return;
174                }
175    
176                this.boatPosRotationIncrements = 3;
177            }
178    
179            this.boatX = par1;
180            this.boatY = par3;
181            this.boatZ = par5;
182            this.boatYaw = (double)par7;
183            this.boatPitch = (double)par8;
184            this.motionX = this.velocityX;
185            this.motionY = this.velocityY;
186            this.motionZ = this.velocityZ;
187        }
188    
189        @SideOnly(Side.CLIENT)
190    
191        /**
192         * Sets the velocity to the args. Args: x, y, z
193         */
194        public void setVelocity(double par1, double par3, double par5)
195        {
196            this.velocityX = this.motionX = par1;
197            this.velocityY = this.motionY = par3;
198            this.velocityZ = this.motionZ = par5;
199        }
200    
201        /**
202         * Called to update the entity's position/logic.
203         */
204        public void onUpdate()
205        {
206            super.onUpdate();
207    
208            if (this.getTimeSinceHit() > 0)
209            {
210                this.setTimeSinceHit(this.getTimeSinceHit() - 1);
211            }
212    
213            if (this.getDamageTaken() > 0)
214            {
215                this.setDamageTaken(this.getDamageTaken() - 1);
216            }
217    
218            this.prevPosX = this.posX;
219            this.prevPosY = this.posY;
220            this.prevPosZ = this.posZ;
221            byte var1 = 5;
222            double var2 = 0.0D;
223    
224            for (int var4 = 0; var4 < var1; ++var4)
225            {
226                double var5 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(var4 + 0) / (double)var1 - 0.125D;
227                double var7 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(var4 + 1) / (double)var1 - 0.125D;
228                AxisAlignedBB var9 = AxisAlignedBB.getAABBPool().addOrModifyAABBInPool(this.boundingBox.minX, var5, this.boundingBox.minZ, this.boundingBox.maxX, var7, this.boundingBox.maxZ);
229    
230                if (this.worldObj.isAABBInMaterial(var9, Material.water))
231                {
232                    var2 += 1.0D / (double)var1;
233                }
234            }
235    
236            double var24 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
237            double var6;
238            double var8;
239    
240            if (var24 > 0.26249999999999996D)
241            {
242                var6 = Math.cos((double)this.rotationYaw * Math.PI / 180.0D);
243                var8 = Math.sin((double)this.rotationYaw * Math.PI / 180.0D);
244    
245                for (int var10 = 0; (double)var10 < 1.0D + var24 * 60.0D; ++var10)
246                {
247                    double var11 = (double)(this.rand.nextFloat() * 2.0F - 1.0F);
248                    double var13 = (double)(this.rand.nextInt(2) * 2 - 1) * 0.7D;
249                    double var15;
250                    double var17;
251    
252                    if (this.rand.nextBoolean())
253                    {
254                        var15 = this.posX - var6 * var11 * 0.8D + var8 * var13;
255                        var17 = this.posZ - var8 * var11 * 0.8D - var6 * var13;
256                        this.worldObj.spawnParticle("splash", var15, this.posY - 0.125D, var17, this.motionX, this.motionY, this.motionZ);
257                    }
258                    else
259                    {
260                        var15 = this.posX + var6 + var8 * var11 * 0.7D;
261                        var17 = this.posZ + var8 - var6 * var11 * 0.7D;
262                        this.worldObj.spawnParticle("splash", var15, this.posY - 0.125D, var17, this.motionX, this.motionY, this.motionZ);
263                    }
264                }
265            }
266    
267            double var12;
268            double var26;
269    
270            if (this.worldObj.isRemote && this.field_70279_a)
271            {
272                if (this.boatPosRotationIncrements > 0)
273                {
274                    var6 = this.posX + (this.boatX - this.posX) / (double)this.boatPosRotationIncrements;
275                    var8 = this.posY + (this.boatY - this.posY) / (double)this.boatPosRotationIncrements;
276                    var26 = this.posZ + (this.boatZ - this.posZ) / (double)this.boatPosRotationIncrements;
277                    var12 = MathHelper.wrapAngleTo180_double(this.boatYaw - (double)this.rotationYaw);
278                    this.rotationYaw = (float)((double)this.rotationYaw + var12 / (double)this.boatPosRotationIncrements);
279                    this.rotationPitch = (float)((double)this.rotationPitch + (this.boatPitch - (double)this.rotationPitch) / (double)this.boatPosRotationIncrements);
280                    --this.boatPosRotationIncrements;
281                    this.setPosition(var6, var8, var26);
282                    this.setRotation(this.rotationYaw, this.rotationPitch);
283                }
284                else
285                {
286                    var6 = this.posX + this.motionX;
287                    var8 = this.posY + this.motionY;
288                    var26 = this.posZ + this.motionZ;
289                    this.setPosition(var6, var8, var26);
290    
291                    if (this.onGround)
292                    {
293                        this.motionX *= 0.5D;
294                        this.motionY *= 0.5D;
295                        this.motionZ *= 0.5D;
296                    }
297    
298                    this.motionX *= 0.9900000095367432D;
299                    this.motionY *= 0.949999988079071D;
300                    this.motionZ *= 0.9900000095367432D;
301                }
302            }
303            else
304            {
305                if (var2 < 1.0D)
306                {
307                    var6 = var2 * 2.0D - 1.0D;
308                    this.motionY += 0.03999999910593033D * var6;
309                }
310                else
311                {
312                    if (this.motionY < 0.0D)
313                    {
314                        this.motionY /= 2.0D;
315                    }
316    
317                    this.motionY += 0.007000000216066837D;
318                }
319    
320                if (this.riddenByEntity != null)
321                {
322                    this.motionX += this.riddenByEntity.motionX * this.field_70276_b;
323                    this.motionZ += this.riddenByEntity.motionZ * this.field_70276_b;
324                }
325    
326                var6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
327    
328                if (var6 > 0.35D)
329                {
330                    var8 = 0.35D / var6;
331                    this.motionX *= var8;
332                    this.motionZ *= var8;
333                    var6 = 0.35D;
334                }
335    
336                if (var6 > var24 && this.field_70276_b < 0.35D)
337                {
338                    this.field_70276_b += (0.35D - this.field_70276_b) / 35.0D;
339    
340                    if (this.field_70276_b > 0.35D)
341                    {
342                        this.field_70276_b = 0.35D;
343                    }
344                }
345                else
346                {
347                    this.field_70276_b -= (this.field_70276_b - 0.07D) / 35.0D;
348    
349                    if (this.field_70276_b < 0.07D)
350                    {
351                        this.field_70276_b = 0.07D;
352                    }
353                }
354    
355                if (this.onGround)
356                {
357                    this.motionX *= 0.5D;
358                    this.motionY *= 0.5D;
359                    this.motionZ *= 0.5D;
360                }
361    
362                this.moveEntity(this.motionX, this.motionY, this.motionZ);
363    
364                if (this.isCollidedHorizontally && var24 > 0.2D)
365                {
366                    if (!this.worldObj.isRemote)
367                    {
368                        this.setDead();
369                        int var25;
370    
371                        for (var25 = 0; var25 < 3; ++var25)
372                        {
373                            this.dropItemWithOffset(Block.planks.blockID, 1, 0.0F);
374                        }
375    
376                        for (var25 = 0; var25 < 2; ++var25)
377                        {
378                            this.dropItemWithOffset(Item.stick.shiftedIndex, 1, 0.0F);
379                        }
380                    }
381                }
382                else
383                {
384                    this.motionX *= 0.9900000095367432D;
385                    this.motionY *= 0.949999988079071D;
386                    this.motionZ *= 0.9900000095367432D;
387                }
388    
389                this.rotationPitch = 0.0F;
390                var8 = (double)this.rotationYaw;
391                var26 = this.prevPosX - this.posX;
392                var12 = this.prevPosZ - this.posZ;
393    
394                if (var26 * var26 + var12 * var12 > 0.001D)
395                {
396                    var8 = (double)((float)(Math.atan2(var12, var26) * 180.0D / Math.PI));
397                }
398    
399                double var14 = MathHelper.wrapAngleTo180_double(var8 - (double)this.rotationYaw);
400    
401                if (var14 > 20.0D)
402                {
403                    var14 = 20.0D;
404                }
405    
406                if (var14 < -20.0D)
407                {
408                    var14 = -20.0D;
409                }
410    
411                this.rotationYaw = (float)((double)this.rotationYaw + var14);
412                this.setRotation(this.rotationYaw, this.rotationPitch);
413    
414                if (!this.worldObj.isRemote)
415                {
416                    List var16 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D));
417    
418                    if (var16 != null && !var16.isEmpty())
419                    {
420                        Iterator var28 = var16.iterator();
421    
422                        while (var28.hasNext())
423                        {
424                            Entity var18 = (Entity)var28.next();
425    
426                            if (var18 != this.riddenByEntity && var18.canBePushed() && var18 instanceof EntityBoat)
427                            {
428                                var18.applyEntityCollision(this);
429                            }
430                        }
431                    }
432    
433                    for (int var27 = 0; var27 < 4; ++var27)
434                    {
435                        int var29 = MathHelper.floor_double(this.posX + ((double)(var27 % 2) - 0.5D) * 0.8D);
436                        int var19 = MathHelper.floor_double(this.posZ + ((double)(var27 / 2) - 0.5D) * 0.8D);
437    
438                        for (int var20 = 0; var20 < 2; ++var20)
439                        {
440                            int var21 = MathHelper.floor_double(this.posY) + var20;
441                            int var22 = this.worldObj.getBlockId(var29, var21, var19);
442                            int var23 = this.worldObj.getBlockMetadata(var29, var21, var19);
443    
444                            if (var22 == Block.snow.blockID)
445                            {
446                                this.worldObj.setBlockWithNotify(var29, var21, var19, 0);
447                            }
448                            else if (var22 == Block.waterlily.blockID)
449                            {
450                                Block.waterlily.dropBlockAsItemWithChance(this.worldObj, var29, var21, var19, var23, 0.3F, 0);
451                                this.worldObj.setBlockWithNotify(var29, var21, var19, 0);
452                            }
453                        }
454                    }
455    
456                    if (this.riddenByEntity != null && this.riddenByEntity.isDead)
457                    {
458                        this.riddenByEntity = null;
459                    }
460                }
461            }
462        }
463    
464        public void updateRiderPosition()
465        {
466            if (this.riddenByEntity != null)
467            {
468                double var1 = Math.cos((double)this.rotationYaw * Math.PI / 180.0D) * 0.4D;
469                double var3 = Math.sin((double)this.rotationYaw * Math.PI / 180.0D) * 0.4D;
470                this.riddenByEntity.setPosition(this.posX + var1, this.posY + this.getMountedYOffset() + this.riddenByEntity.getYOffset(), this.posZ + var3);
471            }
472        }
473    
474        /**
475         * (abstract) Protected helper method to write subclass entity data to NBT.
476         */
477        protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) {}
478    
479        /**
480         * (abstract) Protected helper method to read subclass entity data from NBT.
481         */
482        protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) {}
483    
484        @SideOnly(Side.CLIENT)
485        public float getShadowSize()
486        {
487            return 0.0F;
488        }
489    
490        /**
491         * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
492         */
493        public boolean interact(EntityPlayer par1EntityPlayer)
494        {
495            if (this.riddenByEntity != null && this.riddenByEntity instanceof EntityPlayer && this.riddenByEntity != par1EntityPlayer)
496            {
497                return true;
498            }
499            else
500            {
501                if (!this.worldObj.isRemote)
502                {
503                    par1EntityPlayer.mountEntity(this);
504                }
505    
506                return true;
507            }
508        }
509    
510        /**
511         * Sets the damage taken from the last hit.
512         */
513        public void setDamageTaken(int par1)
514        {
515            this.dataWatcher.updateObject(19, Integer.valueOf(par1));
516        }
517    
518        /**
519         * Gets the damage taken from the last hit.
520         */
521        public int getDamageTaken()
522        {
523            return this.dataWatcher.getWatchableObjectInt(19);
524        }
525    
526        /**
527         * Sets the time to count down from since the last time entity was hit.
528         */
529        public void setTimeSinceHit(int par1)
530        {
531            this.dataWatcher.updateObject(17, Integer.valueOf(par1));
532        }
533    
534        /**
535         * Gets the time since the last hit.
536         */
537        public int getTimeSinceHit()
538        {
539            return this.dataWatcher.getWatchableObjectInt(17);
540        }
541    
542        /**
543         * Sets the forward direction of the entity.
544         */
545        public void setForwardDirection(int par1)
546        {
547            this.dataWatcher.updateObject(18, Integer.valueOf(par1));
548        }
549    
550        /**
551         * Gets the forward direction of the entity.
552         */
553        public int getForwardDirection()
554        {
555            return this.dataWatcher.getWatchableObjectInt(18);
556        }
557    
558        @SideOnly(Side.CLIENT)
559        public void func_70270_d(boolean par1)
560        {
561            this.field_70279_a = par1;
562        }
563    }