    001    package net.minecraft.entity.projectile;
    002
    003    import cpw.mods.fml.relauncher.Side;
    004    import cpw.mods.fml.relauncher.SideOnly;
    005    import java.util.List;
    006    import net.minecraft.entity.Entity;
    007    import net.minecraft.entity.EntityLiving;
    008    import net.minecraft.nbt.NBTTagCompound;
    009    import net.minecraft.nbt.NBTTagDouble;
    010    import net.minecraft.nbt.NBTTagList;
    011    import net.minecraft.util.AxisAlignedBB;
    012    import net.minecraft.util.DamageSource;
    013    import net.minecraft.util.MathHelper;
    014    import net.minecraft.util.MovingObjectPosition;
    015    import net.minecraft.util.Vec3;
    016    import net.minecraft.world.World;
    017
    018    public abstract class EntityFireball extends Entity
    019    {
    020        private int xTile = -1;
    021        private int yTile = -1;
    022        private int zTile = -1;
    023        private int inTile = 0;
    024        private boolean inGround = false;
    025        public EntityLiving shootingEntity;
    026        private int ticksAlive;
    027        private int ticksInAir = 0;
    028        public double accelerationX;
    029        public double accelerationY;
    030        public double accelerationZ;
    031
    032        public EntityFireball(World par1World)
    033        {
    034            super(par1World);
    035            this.setSize(1.0F, 1.0F);
    036        }
    037
    038        protected void entityInit() {}
    039
    040        @SideOnly(Side.CLIENT)
    041
    042        /**
    043         * Checks if the entity is in range to render by using the past in distance and comparing it to its average edge
    044         * length * 64 * renderDistanceWeight Args: distance
    045         */
    046        public boolean isInRangeToRenderDist(double par1)
    047        {
    048            double var3 = this.boundingBox.getAverageEdgeLength() * 4.0D;
    049            var3 *= 64.0D;
    050            return par1 < var3 * var3;
    051        }
    052
    053        public EntityFireball(World par1World, double par2, double par4, double par6, double par8, double par10, double par12)
    054        {
    055            super(par1World);
    056            this.setSize(1.0F, 1.0F);
    057            this.setLocationAndAngles(par2, par4, par6, this.rotationYaw, this.rotationPitch);
    058            this.setPosition(par2, par4, par6);
    059            double var14 = (double)MathHelper.sqrt_double(par8 * par8 + par10 * par10 + par12 * par12);
    060            this.accelerationX = par8 / var14 * 0.1D;
    061            this.accelerationY = par10 / var14 * 0.1D;
    062            this.accelerationZ = par12 / var14 * 0.1D;
    063        }
    064
    065        public EntityFireball(World par1World, EntityLiving par2EntityLiving, double par3, double par5, double par7)
    066        {
    067            super(par1World);
    068            this.shootingEntity = par2EntityLiving;
    069            this.setSize(1.0F, 1.0F);
    070            this.setLocationAndAngles(par2EntityLiving.posX, par2EntityLiving.posY, par2EntityLiving.posZ, par2EntityLiving.rotationYaw, par2EntityLiving.rotationPitch);
    071            this.setPosition(this.posX, this.posY, this.posZ);
    072            this.yOffset = 0.0F;
    073            this.motionX = this.motionY = this.motionZ = 0.0D;
    074            par3 += this.rand.nextGaussian() * 0.4D;
    075            par5 += this.rand.nextGaussian() * 0.4D;
    076            par7 += this.rand.nextGaussian() * 0.4D;
    077            double var9 = (double)MathHelper.sqrt_double(par3 * par3 + par5 * par5 + par7 * par7);
    078            this.accelerationX = par3 / var9 * 0.1D;
    079            this.accelerationY = par5 / var9 * 0.1D;
    080            this.accelerationZ = par7 / var9 * 0.1D;
    081        }
    082
    083        /**
    084         * Called to update the entity's position/logic.
    085         */
    086        public void onUpdate()
    087        {
    088            if (!this.worldObj.isRemote && (this.shootingEntity != null && this.shootingEntity.isDead || !this.worldObj.blockExists((int)this.posX, (int)this.posY, (int)this.posZ)))
    089            {
    090                this.setDead();
    091            }
    092            else
    093            {
    094                super.onUpdate();
    095                this.setFire(1);
    096
    097                if (this.inGround)
    098                {
    099                    int var1 = this.worldObj.getBlockId(this.xTile, this.yTile, this.zTile);
    100
    101                    if (var1 == this.inTile)
    102                    {
    103                        ++this.ticksAlive;
    104
    105                        if (this.ticksAlive == 600)
    106                        {
    107                            this.setDead();
    108                        }
    109
    110                        return;
    111                    }
    112
    113                    this.inGround = false;
    114                    this.motionX *= (double)(this.rand.nextFloat() * 0.2F);
    115                    this.motionY *= (double)(this.rand.nextFloat() * 0.2F);
    116                    this.motionZ *= (double)(this.rand.nextFloat() * 0.2F);
    117                    this.ticksAlive = 0;
    118                    this.ticksInAir = 0;
    119                }
    120                else
    121                {
    122                    ++this.ticksInAir;
    123                }
    124
    125                Vec3 var15 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
    126                Vec3 var2 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
    127                MovingObjectPosition var3 = this.worldObj.rayTraceBlocks(var15, var2);
    128                var15 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
    129                var2 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
    130
    131                if (var3 != null)
    132                {
    133                    var2 = this.worldObj.getWorldVec3Pool().getVecFromPool(var3.hitVec.xCoord, var3.hitVec.yCoord, var3.hitVec.zCoord);
    134                }
    135
    136                Entity var4 = null;
    137                List var5 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.addCoord(this.motionX, this.motionY, this.motionZ).expand(1.0D, 1.0D, 1.0D));
    138                double var6 = 0.0D;
    139
    140                for (int var8 = 0; var8 < var5.size(); ++var8)
    141                {
    142                    Entity var9 = (Entity)var5.get(var8);
    143
    144                    if (var9.canBeCollidedWith() && (!var9.isEntityEqual(this.shootingEntity) || this.ticksInAir >= 25))
    145                    {
    146                        float var10 = 0.3F;
    147                        AxisAlignedBB var11 = var9.boundingBox.expand((double)var10, (double)var10, (double)var10);
    148                        MovingObjectPosition var12 = var11.calculateIntercept(var15, var2);
    149
    150                        if (var12 != null)
    151                        {
    152                            double var13 = var15.distanceTo(var12.hitVec);
    153
    154                            if (var13 < var6 || var6 == 0.0D)
    155                            {
    156                                var4 = var9;
    157                                var6 = var13;
    158                            }
    159                        }
    160                    }
    161                }
    162
    163                if (var4 != null)
    164                {
    165                    var3 = new MovingObjectPosition(var4);
    166                }
    167
    168                if (var3 != null)
    169                {
    170                    this.onImpact(var3);
    171                }
    172
    173                this.posX += this.motionX;
    174                this.posY += this.motionY;
    175                this.posZ += this.motionZ;
    176                float var16 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
    177                this.rotationYaw = (float)(Math.atan2(this.motionZ, this.motionX) * 180.0D / Math.PI) + 90.0F;
    178
    179                for (this.rotationPitch = (float)(Math.atan2((double)var16, this.motionY) * 180.0D / Math.PI) - 90.0F; this.rotationPitch - this.prevRotationPitch < -180.0F; this.prevRotationPitch -= 360.0F)
    180                {
    181                    ;
    182                }
    183
    184                while (this.rotationPitch - this.prevRotationPitch >= 180.0F)
    185                {
    186                    this.prevRotationPitch += 360.0F;
    187                }
    188
    189                while (this.rotationYaw - this.prevRotationYaw < -180.0F)
    190                {
    191                    this.prevRotationYaw -= 360.0F;
    192                }
    193
    194                while (this.rotationYaw - this.prevRotationYaw >= 180.0F)
    195                {
    196                    this.prevRotationYaw += 360.0F;
    197                }
    198
    199                this.rotationPitch = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * 0.2F;
    200                this.rotationYaw = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * 0.2F;
    201                float var17 = this.getMotionFactor();
    202
    203                if (this.isInWater())
    204                {
    205                    for (int var19 = 0; var19 < 4; ++var19)
    206                    {
    207                        float var18 = 0.25F;
    208                        this.worldObj.spawnParticle("bubble", this.posX - this.motionX * (double)var18, this.posY - this.motionY * (double)var18, this.posZ - this.motionZ * (double)var18, this.motionX, this.motionY, this.motionZ);
    209                    }
    210
    211                    var17 = 0.8F;
    212                }
    213
    214                this.motionX += this.accelerationX;
    215                this.motionY += this.accelerationY;
    216                this.motionZ += this.accelerationZ;
    217                this.motionX *= (double)var17;
    218                this.motionY *= (double)var17;
    219                this.motionZ *= (double)var17;
    220                this.worldObj.spawnParticle("smoke", this.posX, this.posY + 0.5D, this.posZ, 0.0D, 0.0D, 0.0D);
    221                this.setPosition(this.posX, this.posY, this.posZ);
    222            }
    223        }
    224
    225        /**
    226         * Return the motion factor for this projectile. The factor is multiplied by the original motion.
    227         */
    228        protected float getMotionFactor()
    229        {
    230            return 0.95F;
    231        }
    232
    233        /**
    234         * Called when this EntityFireball hits a block or entity.
    235         */
    236        protected abstract void onImpact(MovingObjectPosition var1);
    237
    238        /**
    239         * (abstract) Protected helper method to write subclass entity data to NBT.
    240         */
    241        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    242        {
    243            par1NBTTagCompound.setShort("xTile", (short)this.xTile);
    244            par1NBTTagCompound.setShort("yTile", (short)this.yTile);
    245            par1NBTTagCompound.setShort("zTile", (short)this.zTile);
    246            par1NBTTagCompound.setByte("inTile", (byte)this.inTile);
    247            par1NBTTagCompound.setByte("inGround", (byte)(this.inGround ? 1 : 0));
    248            par1NBTTagCompound.setTag("direction", this.newDoubleNBTList(new double[] {this.motionX, this.motionY, this.motionZ}));
    249        }
    250
    251        /**
    252         * (abstract) Protected helper method to read subclass entity data from NBT.
    253         */
    254        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    255        {
    256            this.xTile = par1NBTTagCompound.getShort("xTile");
    257            this.yTile = par1NBTTagCompound.getShort("yTile");
    258            this.zTile = par1NBTTagCompound.getShort("zTile");
    259            this.inTile = par1NBTTagCompound.getByte("inTile") & 255;
    260            this.inGround = par1NBTTagCompound.getByte("inGround") == 1;
    261
    262            if (par1NBTTagCompound.hasKey("direction"))
    263            {
    264                NBTTagList var2 = par1NBTTagCompound.getTagList("direction");
    265                this.motionX = ((NBTTagDouble)var2.tagAt(0)).data;
    266                this.motionY = ((NBTTagDouble)var2.tagAt(1)).data;
    267                this.motionZ = ((NBTTagDouble)var2.tagAt(2)).data;
    268            }
    269            else
    270            {
    271                this.setDead();
    272            }
    273        }
    274
    275        /**
    276         * Returns true if other Entities should be prevented from moving through this Entity.
    277         */
    278        public boolean canBeCollidedWith()
    279        {
    280            return true;
    281        }
    282
    283        public float getCollisionBorderSize()
    284        {
    285            return 1.0F;
    286        }
    287
    288        /**
    289         * Called when the entity is attacked.
    290         */
    291        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    292        {
    293            if (this.func_85032_ar())
    294            {
    295                return false;
    296            }
    297            else
    298            {
    299                this.setBeenAttacked();
    300
    301                if (par1DamageSource.getEntity() != null)
    302                {
    303                    Vec3 var3 = par1DamageSource.getEntity().getLookVec();
    304
    305                    if (var3 != null)
    306                    {
    307                        this.motionX = var3.xCoord;
    308                        this.motionY = var3.yCoord;
    309                        this.motionZ = var3.zCoord;
    310                        this.accelerationX = this.motionX * 0.1D;
    311                        this.accelerationY = this.motionY * 0.1D;
    312                        this.accelerationZ = this.motionZ * 0.1D;
    313                    }
    314
    315                    if (par1DamageSource.getEntity() instanceof EntityLiving)
    316                    {
    317                        this.shootingEntity = (EntityLiving)par1DamageSource.getEntity();
    318                    }
    319
    320                    return true;
    321                }
    322                else
    323                {
    324                    return false;
    325                }
    326            }
    327        }
    328
    329        @SideOnly(Side.CLIENT)
    330        public float getShadowSize()
    331        {
    332            return 0.0F;
    333        }
    334
    335        /**
    336         * Gets how bright this entity is.
    337         */
    338        public float getBrightness(float par1)
    339        {
    340            return 1.0F;
    341        }
    342
    343        @SideOnly(Side.CLIENT)
    344        public int getBrightnessForRender(float par1)
    345        {
    346            return 15728880;
    347        }
    348    }