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