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