    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    }