    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    }