    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    }