    001package net.minecraft.entity.item;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.List;
    006import net.minecraft.block.Block;
    007import net.minecraft.block.material.Material;
    008import net.minecraft.entity.Entity;
    009import net.minecraft.entity.player.EntityPlayer;
    010import net.minecraft.item.Item;
    011import net.minecraft.nbt.NBTTagCompound;
    012import net.minecraft.util.AxisAlignedBB;
    013import net.minecraft.util.DamageSource;
    014import net.minecraft.util.MathHelper;
    015import net.minecraft.world.World;
    016
    017public 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.isEntityInvulnerable())
    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.itemID, 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.itemID, 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}