    001    package net.minecraft.entity.item;
    002
    003    import cpw.mods.fml.relauncher.Side;
    004    import cpw.mods.fml.relauncher.SideOnly;
    005    import java.util.List;
    006    import net.minecraft.block.Block;
    007    import net.minecraft.block.material.Material;
    008    import net.minecraft.entity.Entity;
    009    import net.minecraft.entity.player.EntityPlayer;
    010    import net.minecraft.item.Item;
    011    import net.minecraft.nbt.NBTTagCompound;
    012    import net.minecraft.util.AxisAlignedBB;
    013    import net.minecraft.util.DamageSource;
    014    import net.minecraft.util.MathHelper;
    015    import net.minecraft.world.World;
    016
    017    public class EntityBoat extends Entity
    018    {
    019        private boolean field_70279_a;
    020        private double field_70276_b;
    021        private int boatPosRotationIncrements;
    022        private double boatX;
    023        private double boatY;
    024        private double boatZ;
    025        private double boatYaw;
    026        private double boatPitch;
    027        @SideOnly(Side.CLIENT)
    028        private double velocityX;
    029        @SideOnly(Side.CLIENT)
    030        private double velocityY;
    031        @SideOnly(Side.CLIENT)
    032        private double velocityZ;
    033
    034        public EntityBoat(World par1World)
    035        {
    036            super(par1World);
    037            this.field_70279_a = true;
    038            this.field_70276_b = 0.07D;
    039            this.preventEntitySpawning = true;
    040            this.setSize(1.5F, 0.6F);
    041            this.yOffset = this.height / 2.0F;
    042        }
    043
    044        /**
    045         * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
    046         * prevent them from trampling crops
    047         */
    048        protected boolean canTriggerWalking()
    049        {
    050            return false;
    051        }
    052
    053        protected void entityInit()
    054        {
    055            this.dataWatcher.addObject(17, new Integer(0));
    056            this.dataWatcher.addObject(18, new Integer(1));
    057            this.dataWatcher.addObject(19, new Integer(0));
    058        }
    059
    060        /**
    061         * Returns a boundingBox used to collide the entity with other entities and blocks. This enables the entity to be
    062         * pushable on contact, like boats or minecarts.
    063         */
    064        public AxisAlignedBB getCollisionBox(Entity par1Entity)
    065        {
    066            return par1Entity.boundingBox;
    067        }
    068
    069        /**
    070         * returns the bounding box for this entity
    071         */
    072        public AxisAlignedBB getBoundingBox()
    073        {
    074            return this.boundingBox;
    075        }
    076
    077        /**
    078         * Returns true if this entity should push and be pushed by other entities when colliding.
    079         */
    080        public boolean canBePushed()
    081        {
    082            return true;
    083        }
    084
    085        public EntityBoat(World par1World, double par2, double par4, double par6)
    086        {
    087            this(par1World);
    088            this.setPosition(par2, par4 + (double)this.yOffset, par6);
    089            this.motionX = 0.0D;
    090            this.motionY = 0.0D;
    091            this.motionZ = 0.0D;
    092            this.prevPosX = par2;
    093            this.prevPosY = par4;
    094            this.prevPosZ = par6;
    095        }
    096
    097        /**
    098         * Returns the Y offset from the entity's position for any entity riding this one.
    099         */
    100        public double getMountedYOffset()
    101        {
    102            return (double)this.height * 0.0D - 0.30000001192092896D;
    103        }
    104
    105        /**
    106         * Called when the entity is attacked.
    107         */
    108        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    109        {
    110            if (this.func_85032_ar())
    111            {
    112                return false;
    113            }
    114            else if (!this.worldObj.isRemote && !this.isDead)
    115            {
    116                this.setForwardDirection(-this.getForwardDirection());
    117                this.setTimeSinceHit(10);
    118                this.setDamageTaken(this.getDamageTaken() + par2 * 10);
    119                this.setBeenAttacked();
    120
    121                if (par1DamageSource.getEntity() instanceof EntityPlayer && ((EntityPlayer)par1DamageSource.getEntity()).capabilities.isCreativeMode)
    122                {
    123                    this.setDamageTaken(100);
    124                }
    125
    126                if (this.getDamageTaken() > 40)
    127                {
    128                    if (this.riddenByEntity != null)
    129                    {
    130                        this.riddenByEntity.mountEntity(this);
    131                    }
    132
    133                    this.dropItemWithOffset(Item.boat.shiftedIndex, 1, 0.0F);
    134                    this.setDead();
    135                }
    136
    137                return true;
    138            }
    139            else
    140            {
    141                return true;
    142            }
    143        }
    144
    145        @SideOnly(Side.CLIENT)
    146
    147        /**
    148         * Setups the entity to do the hurt animation. Only used by packets in multiplayer.
    149         */
    150        public void performHurtAnimation()
    151        {
    152            this.setForwardDirection(-this.getForwardDirection());
    153            this.setTimeSinceHit(10);
    154            this.setDamageTaken(this.getDamageTaken() * 11);
    155        }
    156
    157        /**
    158         * Returns true if other Entities should be prevented from moving through this Entity.
    159         */
    160        public boolean canBeCollidedWith()
    161        {
    162            return !this.isDead;
    163        }
    164
    165        @SideOnly(Side.CLIENT)
    166
    167        /**
    168         * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX,
    169         * posY, posZ, yaw, pitch
    170         */
    171        public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
    172        {
    173            if (this.field_70279_a)
    174            {
    175                this.boatPosRotationIncrements = par9 + 5;
    176            }
    177            else
    178            {
    179                double var10 = par1 - this.posX;
    180                double var12 = par3 - this.posY;
    181                double var14 = par5 - this.posZ;
    182                double var16 = var10 * var10 + var12 * var12 + var14 * var14;
    183
    184                if (var16 <= 1.0D)
    185                {
    186                    return;
    187                }
    188
    189                this.boatPosRotationIncrements = 3;
    190            }
    191
    192            this.boatX = par1;
    193            this.boatY = par3;
    194            this.boatZ = par5;
    195            this.boatYaw = (double)par7;
    196            this.boatPitch = (double)par8;
    197            this.motionX = this.velocityX;
    198            this.motionY = this.velocityY;
    199            this.motionZ = this.velocityZ;
    200        }
    201
    202        @SideOnly(Side.CLIENT)
    203
    204        /**
    205         * Sets the velocity to the args. Args: x, y, z
    206         */
    207        public void setVelocity(double par1, double par3, double par5)
    208        {
    209            this.velocityX = this.motionX = par1;
    210            this.velocityY = this.motionY = par3;
    211            this.velocityZ = this.motionZ = par5;
    212        }
    213
    214        /**
    215         * Called to update the entity's position/logic.
    216         */
    217        public void onUpdate()
    218        {
    219            super.onUpdate();
    220
    221            if (this.getTimeSinceHit() > 0)
    222            {
    223                this.setTimeSinceHit(this.getTimeSinceHit() - 1);
    224            }
    225
    226            if (this.getDamageTaken() > 0)
    227            {
    228                this.setDamageTaken(this.getDamageTaken() - 1);
    229            }
    230
    231            this.prevPosX = this.posX;
    232            this.prevPosY = this.posY;
    233            this.prevPosZ = this.posZ;
    234            byte var1 = 5;
    235            double var2 = 0.0D;
    236
    237            for (int var4 = 0; var4 < var1; ++var4)
    238            {
    239                double var5 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(var4 + 0) / (double)var1 - 0.125D;
    240                double var7 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(var4 + 1) / (double)var1 - 0.125D;
    241                AxisAlignedBB var9 = AxisAlignedBB.getAABBPool().addOrModifyAABBInPool(this.boundingBox.minX, var5, this.boundingBox.minZ, this.boundingBox.maxX, var7, this.boundingBox.maxZ);
    242
    243                if (this.worldObj.isAABBInMaterial(var9, Material.water))
    244                {
    245                    var2 += 1.0D / (double)var1;
    246                }
    247            }
    248
    249            double var24 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
    250            double var6;
    251            double var8;
    252
    253            if (var24 > 0.26249999999999996D)
    254            {
    255                var6 = Math.cos((double)this.rotationYaw * Math.PI / 180.0D);
    256                var8 = Math.sin((double)this.rotationYaw * Math.PI / 180.0D);
    257
    258                for (int var10 = 0; (double)var10 < 1.0D + var24 * 60.0D; ++var10)
    259                {
    260                    double var11 = (double)(this.rand.nextFloat() * 2.0F - 1.0F);
    261                    double var13 = (double)(this.rand.nextInt(2) * 2 - 1) * 0.7D;
    262                    double var15;
    263                    double var17;
    264
    265                    if (this.rand.nextBoolean())
    266                    {
    267                        var15 = this.posX - var6 * var11 * 0.8D + var8 * var13;
    268                        var17 = this.posZ - var8 * var11 * 0.8D - var6 * var13;
    269                        this.worldObj.spawnParticle("splash", var15, this.posY - 0.125D, var17, this.motionX, this.motionY, this.motionZ);
    270                    }
    271                    else
    272                    {
    273                        var15 = this.posX + var6 + var8 * var11 * 0.7D;
    274                        var17 = this.posZ + var8 - var6 * var11 * 0.7D;
    275                        this.worldObj.spawnParticle("splash", var15, this.posY - 0.125D, var17, this.motionX, this.motionY, this.motionZ);
    276                    }
    277                }
    278            }
    279
    280            double var12;
    281            double var26;
    282
    283            if (this.worldObj.isRemote && this.field_70279_a)
    284            {
    285                if (this.boatPosRotationIncrements > 0)
    286                {
    287                    var6 = this.posX + (this.boatX - this.posX) / (double)this.boatPosRotationIncrements;
    288                    var8 = this.posY + (this.boatY - this.posY) / (double)this.boatPosRotationIncrements;
    289                    var26 = this.posZ + (this.boatZ - this.posZ) / (double)this.boatPosRotationIncrements;
    290                    var12 = MathHelper.wrapAngleTo180_double(this.boatYaw - (double)this.rotationYaw);
    291                    this.rotationYaw = (float)((double)this.rotationYaw + var12 / (double)this.boatPosRotationIncrements);
    292                    this.rotationPitch = (float)((double)this.rotationPitch + (this.boatPitch - (double)this.rotationPitch) / (double)this.boatPosRotationIncrements);
    293                    --this.boatPosRotationIncrements;
    294                    this.setPosition(var6, var8, var26);
    295                    this.setRotation(this.rotationYaw, this.rotationPitch);
    296                }
    297                else
    298                {
    299                    var6 = this.posX + this.motionX;
    300                    var8 = this.posY + this.motionY;
    301                    var26 = this.posZ + this.motionZ;
    302                    this.setPosition(var6, var8, var26);
    303
    304                    if (this.onGround)
    305                    {
    306                        this.motionX *= 0.5D;
    307                        this.motionY *= 0.5D;
    308                        this.motionZ *= 0.5D;
    309                    }
    310
    311                    this.motionX *= 0.9900000095367432D;
    312                    this.motionY *= 0.949999988079071D;
    313                    this.motionZ *= 0.9900000095367432D;
    314                }
    315            }
    316            else
    317            {
    318                if (var2 < 1.0D)
    319                {
    320                    var6 = var2 * 2.0D - 1.0D;
    321                    this.motionY += 0.03999999910593033D * var6;
    322                }
    323                else
    324                {
    325                    if (this.motionY < 0.0D)
    326                    {
    327                        this.motionY /= 2.0D;
    328                    }
    329
    330                    this.motionY += 0.007000000216066837D;
    331                }
    332
    333                if (this.riddenByEntity != null)
    334                {
    335                    this.motionX += this.riddenByEntity.motionX * this.field_70276_b;
    336                    this.motionZ += this.riddenByEntity.motionZ * this.field_70276_b;
    337                }
    338
    339                var6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
    340
    341                if (var6 > 0.35D)
    342                {
    343                    var8 = 0.35D / var6;
    344                    this.motionX *= var8;
    345                    this.motionZ *= var8;
    346                    var6 = 0.35D;
    347                }
    348
    349                if (var6 > var24 && this.field_70276_b < 0.35D)
    350                {
    351                    this.field_70276_b += (0.35D - this.field_70276_b) / 35.0D;
    352
    353                    if (this.field_70276_b > 0.35D)
    354                    {
    355                        this.field_70276_b = 0.35D;
    356                    }
    357                }
    358                else
    359                {
    360                    this.field_70276_b -= (this.field_70276_b - 0.07D) / 35.0D;
    361
    362                    if (this.field_70276_b < 0.07D)
    363                    {
    364                        this.field_70276_b = 0.07D;
    365                    }
    366                }
    367
    368                if (this.onGround)
    369                {
    370                    this.motionX *= 0.5D;
    371                    this.motionY *= 0.5D;
    372                    this.motionZ *= 0.5D;
    373                }
    374
    375                this.moveEntity(this.motionX, this.motionY, this.motionZ);
    376
    377                if (this.isCollidedHorizontally && var24 > 0.2D)
    378                {
    379                    if (!this.worldObj.isRemote)
    380                    {
    381                        this.setDead();
    382                        int var25;
    383
    384                        for (var25 = 0; var25 < 3; ++var25)
    385                        {
    386                            this.dropItemWithOffset(Block.planks.blockID, 1, 0.0F);
    387                        }
    388
    389                        for (var25 = 0; var25 < 2; ++var25)
    390                        {
    391                            this.dropItemWithOffset(Item.stick.shiftedIndex, 1, 0.0F);
    392                        }
    393                    }
    394                }
    395                else
    396                {
    397                    this.motionX *= 0.9900000095367432D;
    398                    this.motionY *= 0.949999988079071D;
    399                    this.motionZ *= 0.9900000095367432D;
    400                }
    401
    402                this.rotationPitch = 0.0F;
    403                var8 = (double)this.rotationYaw;
    404                var26 = this.prevPosX - this.posX;
    405                var12 = this.prevPosZ - this.posZ;
    406
    407                if (var26 * var26 + var12 * var12 > 0.001D)
    408                {
    409                    var8 = (double)((float)(Math.atan2(var12, var26) * 180.0D / Math.PI));
    410                }
    411
    412                double var14 = MathHelper.wrapAngleTo180_double(var8 - (double)this.rotationYaw);
    413
    414                if (var14 > 20.0D)
    415                {
    416                    var14 = 20.0D;
    417                }
    418
    419                if (var14 < -20.0D)
    420                {
    421                    var14 = -20.0D;
    422                }
    423
    424                this.rotationYaw = (float)((double)this.rotationYaw + var14);
    425                this.setRotation(this.rotationYaw, this.rotationPitch);
    426
    427                if (!this.worldObj.isRemote)
    428                {
    429                    List var16 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D));
    430                    int var27;
    431
    432                    if (var16 != null && !var16.isEmpty())
    433                    {
    434                        for (var27 = 0; var27 < var16.size(); ++var27)
    435                        {
    436                            Entity var18 = (Entity)var16.get(var27);
    437
    438                            if (var18 != this.riddenByEntity && var18.canBePushed() && var18 instanceof EntityBoat)
    439                            {
    440                                var18.applyEntityCollision(this);
    441                            }
    442                        }
    443                    }
    444
    445                    for (var27 = 0; var27 < 4; ++var27)
    446                    {
    447                        int var28 = MathHelper.floor_double(this.posX + ((double)(var27 % 2) - 0.5D) * 0.8D);
    448                        int var19 = MathHelper.floor_double(this.posZ + ((double)(var27 / 2) - 0.5D) * 0.8D);
    449
    450                        for (int var20 = 0; var20 < 2; ++var20)
    451                        {
    452                            int var21 = MathHelper.floor_double(this.posY) + var20;
    453                            int var22 = this.worldObj.getBlockId(var28, var21, var19);
    454                            int var23 = this.worldObj.getBlockMetadata(var28, var21, var19);
    455
    456                            if (var22 == Block.snow.blockID)
    457                            {
    458                                this.worldObj.setBlockWithNotify(var28, var21, var19, 0);
    459                            }
    460                            else if (var22 == Block.waterlily.blockID)
    461                            {
    462                                Block.waterlily.dropBlockAsItemWithChance(this.worldObj, var28, var21, var19, var23, 0.3F, 0);
    463                                this.worldObj.setBlockWithNotify(var28, var21, var19, 0);
    464                            }
    465                        }
    466                    }
    467
    468                    if (this.riddenByEntity != null && this.riddenByEntity.isDead)
    469                    {
    470                        this.riddenByEntity = null;
    471                    }
    472                }
    473            }
    474        }
    475
    476        public void updateRiderPosition()
    477        {
    478            if (this.riddenByEntity != null)
    479            {
    480                double var1 = Math.cos((double)this.rotationYaw * Math.PI / 180.0D) * 0.4D;
    481                double var3 = Math.sin((double)this.rotationYaw * Math.PI / 180.0D) * 0.4D;
    482                this.riddenByEntity.setPosition(this.posX + var1, this.posY + this.getMountedYOffset() + this.riddenByEntity.getYOffset(), this.posZ + var3);
    483            }
    484        }
    485
    486        /**
    487         * (abstract) Protected helper method to write subclass entity data to NBT.
    488         */
    489        protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) {}
    490
    491        /**
    492         * (abstract) Protected helper method to read subclass entity data from NBT.
    493         */
    494        protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) {}
    495
    496        /**
    497         * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
    498         */
    499        public boolean interact(EntityPlayer par1EntityPlayer)
    500        {
    501            if (this.riddenByEntity != null && this.riddenByEntity instanceof EntityPlayer && this.riddenByEntity != par1EntityPlayer)
    502            {
    503                return true;
    504            }
    505            else
    506            {
    507                if (!this.worldObj.isRemote)
    508                {
    509                    par1EntityPlayer.mountEntity(this);
    510                }
    511
    512                return true;
    513            }
    514        }
    515
    516        /**
    517         * Sets the damage taken from the last hit.
    518         */
    519        public void setDamageTaken(int par1)
    520        {
    521            this.dataWatcher.updateObject(19, Integer.valueOf(par1));
    522        }
    523
    524        @SideOnly(Side.CLIENT)
    525        public float getShadowSize()
    526        {
    527            return 0.0F;
    528        }
    529
    530        /**
    531         * Gets the damage taken from the last hit.
    532         */
    533        public int getDamageTaken()
    534        {
    535            return this.dataWatcher.getWatchableObjectInt(19);
    536        }
    537
    538        /**
    539         * Sets the time to count down from since the last time entity was hit.
    540         */
    541        public void setTimeSinceHit(int par1)
    542        {
    543            this.dataWatcher.updateObject(17, Integer.valueOf(par1));
    544        }
    545
    546        /**
    547         * Gets the time since the last hit.
    548         */
    549        public int getTimeSinceHit()
    550        {
    551            return this.dataWatcher.getWatchableObjectInt(17);
    552        }
    553
    554        /**
    555         * Sets the forward direction of the entity.
    556         */
    557        public void setForwardDirection(int par1)
    558        {
    559            this.dataWatcher.updateObject(18, Integer.valueOf(par1));
    560        }
    561
    562        /**
    563         * Gets the forward direction of the entity.
    564         */
    565        public int getForwardDirection()
    566        {
    567            return this.dataWatcher.getWatchableObjectInt(18);
    568        }
    569
    570        @SideOnly(Side.CLIENT)
    571        public void func_70270_d(boolean par1)
    572        {
    573            this.field_70279_a = par1;
    574        }
    575    }