001package net.minecraft.entity.projectile;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import java.util.List;
006import net.minecraft.block.material.Material;
007import net.minecraft.entity.Entity;
008import net.minecraft.entity.item.EntityItem;
009import net.minecraft.entity.item.EntityXPOrb;
010import net.minecraft.entity.player.EntityPlayer;
011import net.minecraft.item.Item;
012import net.minecraft.item.ItemStack;
013import net.minecraft.nbt.NBTTagCompound;
014import net.minecraft.stats.StatList;
015import net.minecraft.util.AxisAlignedBB;
016import net.minecraft.util.DamageSource;
017import net.minecraft.util.MathHelper;
018import net.minecraft.util.MovingObjectPosition;
019import net.minecraft.util.Vec3;
020import net.minecraft.world.World;
021
022public class EntityFishHook extends Entity
023{
024    /** The tile this entity is on, X position */
025    private int xTile;
026
027    /** The tile this entity is on, Y position */
028    private int yTile;
029
030    /** The tile this entity is on, Z position */
031    private int zTile;
032    private int inTile;
033    private boolean inGround;
034    public int shake;
035    public EntityPlayer angler;
036    private int ticksInGround;
037    private int ticksInAir;
038
039    /** the number of ticks remaining until this fish can no longer be caught */
040    private int ticksCatchable;
041
042    /**
043     * The entity that the fishing rod is connected to, if any. When you right click on the fishing rod and the hook
044     * falls on to an entity, this it that entity.
045     */
046    public Entity bobber;
047    private int fishPosRotationIncrements;
048    private double fishX;
049    private double fishY;
050    private double fishZ;
051    private double fishYaw;
052    private double fishPitch;
053    @SideOnly(Side.CLIENT)
054    private double velocityX;
055    @SideOnly(Side.CLIENT)
056    private double velocityY;
057    @SideOnly(Side.CLIENT)
058    private double velocityZ;
059
060    public EntityFishHook(World par1World)
061    {
062        super(par1World);
063        this.xTile = -1;
064        this.yTile = -1;
065        this.zTile = -1;
066        this.inTile = 0;
067        this.inGround = false;
068        this.shake = 0;
069        this.ticksInAir = 0;
070        this.ticksCatchable = 0;
071        this.bobber = null;
072        this.setSize(0.25F, 0.25F);
073        this.ignoreFrustumCheck = true;
074    }
075
076    @SideOnly(Side.CLIENT)
077    public EntityFishHook(World par1World, double par2, double par4, double par6, EntityPlayer par8EntityPlayer)
078    {
079        this(par1World);
080        this.setPosition(par2, par4, par6);
081        this.ignoreFrustumCheck = true;
082        this.angler = par8EntityPlayer;
083        par8EntityPlayer.fishEntity = this;
084    }
085
086    public EntityFishHook(World par1World, EntityPlayer par2EntityPlayer)
087    {
088        super(par1World);
089        this.xTile = -1;
090        this.yTile = -1;
091        this.zTile = -1;
092        this.inTile = 0;
093        this.inGround = false;
094        this.shake = 0;
095        this.ticksInAir = 0;
096        this.ticksCatchable = 0;
097        this.bobber = null;
098        this.ignoreFrustumCheck = true;
099        this.angler = par2EntityPlayer;
100        this.angler.fishEntity = this;
101        this.setSize(0.25F, 0.25F);
102        this.setLocationAndAngles(par2EntityPlayer.posX, par2EntityPlayer.posY + 1.62D - (double)par2EntityPlayer.yOffset, par2EntityPlayer.posZ, par2EntityPlayer.rotationYaw, par2EntityPlayer.rotationPitch);
103        this.posX -= (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F);
104        this.posY -= 0.10000000149011612D;
105        this.posZ -= (double)(MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F);
106        this.setPosition(this.posX, this.posY, this.posZ);
107        this.yOffset = 0.0F;
108        float var3 = 0.4F;
109        this.motionX = (double)(-MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI) * var3);
110        this.motionZ = (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI) * var3);
111        this.motionY = (double)(-MathHelper.sin(this.rotationPitch / 180.0F * (float)Math.PI) * var3);
112        this.calculateVelocity(this.motionX, this.motionY, this.motionZ, 1.5F, 1.0F);
113    }
114
115    protected void entityInit() {}
116
117    @SideOnly(Side.CLIENT)
118
119    /**
120     * Checks if the entity is in range to render by using the past in distance and comparing it to its average edge
121     * length * 64 * renderDistanceWeight Args: distance
122     */
123    public boolean isInRangeToRenderDist(double par1)
124    {
125        double var3 = this.boundingBox.getAverageEdgeLength() * 4.0D;
126        var3 *= 64.0D;
127        return par1 < var3 * var3;
128    }
129
130    public void calculateVelocity(double par1, double par3, double par5, float par7, float par8)
131    {
132        float var9 = MathHelper.sqrt_double(par1 * par1 + par3 * par3 + par5 * par5);
133        par1 /= (double)var9;
134        par3 /= (double)var9;
135        par5 /= (double)var9;
136        par1 += this.rand.nextGaussian() * 0.007499999832361937D * (double)par8;
137        par3 += this.rand.nextGaussian() * 0.007499999832361937D * (double)par8;
138        par5 += this.rand.nextGaussian() * 0.007499999832361937D * (double)par8;
139        par1 *= (double)par7;
140        par3 *= (double)par7;
141        par5 *= (double)par7;
142        this.motionX = par1;
143        this.motionY = par3;
144        this.motionZ = par5;
145        float var10 = MathHelper.sqrt_double(par1 * par1 + par5 * par5);
146        this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(par1, par5) * 180.0D / Math.PI);
147        this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(par3, (double)var10) * 180.0D / Math.PI);
148        this.ticksInGround = 0;
149    }
150
151    @SideOnly(Side.CLIENT)
152
153    /**
154     * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX,
155     * posY, posZ, yaw, pitch
156     */
157    public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
158    {
159        this.fishX = par1;
160        this.fishY = par3;
161        this.fishZ = par5;
162        this.fishYaw = (double)par7;
163        this.fishPitch = (double)par8;
164        this.fishPosRotationIncrements = par9;
165        this.motionX = this.velocityX;
166        this.motionY = this.velocityY;
167        this.motionZ = this.velocityZ;
168    }
169
170    @SideOnly(Side.CLIENT)
171
172    /**
173     * Sets the velocity to the args. Args: x, y, z
174     */
175    public void setVelocity(double par1, double par3, double par5)
176    {
177        this.velocityX = this.motionX = par1;
178        this.velocityY = this.motionY = par3;
179        this.velocityZ = this.motionZ = par5;
180    }
181
182    /**
183     * Called to update the entity's position/logic.
184     */
185    public void onUpdate()
186    {
187        super.onUpdate();
188
189        if (this.fishPosRotationIncrements > 0)
190        {
191            double var21 = this.posX + (this.fishX - this.posX) / (double)this.fishPosRotationIncrements;
192            double var22 = this.posY + (this.fishY - this.posY) / (double)this.fishPosRotationIncrements;
193            double var23 = this.posZ + (this.fishZ - this.posZ) / (double)this.fishPosRotationIncrements;
194            double var7 = MathHelper.wrapAngleTo180_double(this.fishYaw - (double)this.rotationYaw);
195            this.rotationYaw = (float)((double)this.rotationYaw + var7 / (double)this.fishPosRotationIncrements);
196            this.rotationPitch = (float)((double)this.rotationPitch + (this.fishPitch - (double)this.rotationPitch) / (double)this.fishPosRotationIncrements);
197            --this.fishPosRotationIncrements;
198            this.setPosition(var21, var22, var23);
199            this.setRotation(this.rotationYaw, this.rotationPitch);
200        }
201        else
202        {
203            if (!this.worldObj.isRemote)
204            {
205                ItemStack var1 = this.angler.getCurrentEquippedItem();
206
207                if (this.angler.isDead || !this.angler.isEntityAlive() || var1 == null || var1.getItem() != Item.fishingRod || this.getDistanceSqToEntity(this.angler) > 1024.0D)
208                {
209                    this.setDead();
210                    this.angler.fishEntity = null;
211                    return;
212                }
213
214                if (this.bobber != null)
215                {
216                    if (!this.bobber.isDead)
217                    {
218                        this.posX = this.bobber.posX;
219                        this.posY = this.bobber.boundingBox.minY + (double)this.bobber.height * 0.8D;
220                        this.posZ = this.bobber.posZ;
221                        return;
222                    }
223
224                    this.bobber = null;
225                }
226            }
227
228            if (this.shake > 0)
229            {
230                --this.shake;
231            }
232
233            if (this.inGround)
234            {
235                int var19 = this.worldObj.getBlockId(this.xTile, this.yTile, this.zTile);
236
237                if (var19 == this.inTile)
238                {
239                    ++this.ticksInGround;
240
241                    if (this.ticksInGround == 1200)
242                    {
243                        this.setDead();
244                    }
245
246                    return;
247                }
248
249                this.inGround = false;
250                this.motionX *= (double)(this.rand.nextFloat() * 0.2F);
251                this.motionY *= (double)(this.rand.nextFloat() * 0.2F);
252                this.motionZ *= (double)(this.rand.nextFloat() * 0.2F);
253                this.ticksInGround = 0;
254                this.ticksInAir = 0;
255            }
256            else
257            {
258                ++this.ticksInAir;
259            }
260
261            Vec3 var20 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
262            Vec3 var2 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
263            MovingObjectPosition var3 = this.worldObj.rayTraceBlocks(var20, var2);
264            var20 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
265            var2 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
266
267            if (var3 != null)
268            {
269                var2 = this.worldObj.getWorldVec3Pool().getVecFromPool(var3.hitVec.xCoord, var3.hitVec.yCoord, var3.hitVec.zCoord);
270            }
271
272            Entity var4 = null;
273            List var5 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.addCoord(this.motionX, this.motionY, this.motionZ).expand(1.0D, 1.0D, 1.0D));
274            double var6 = 0.0D;
275            double var13;
276
277            for (int var8 = 0; var8 < var5.size(); ++var8)
278            {
279                Entity var9 = (Entity)var5.get(var8);
280
281                if (var9.canBeCollidedWith() && (var9 != this.angler || this.ticksInAir >= 5))
282                {
283                    float var10 = 0.3F;
284                    AxisAlignedBB var11 = var9.boundingBox.expand((double)var10, (double)var10, (double)var10);
285                    MovingObjectPosition var12 = var11.calculateIntercept(var20, var2);
286
287                    if (var12 != null)
288                    {
289                        var13 = var20.distanceTo(var12.hitVec);
290
291                        if (var13 < var6 || var6 == 0.0D)
292                        {
293                            var4 = var9;
294                            var6 = var13;
295                        }
296                    }
297                }
298            }
299
300            if (var4 != null)
301            {
302                var3 = new MovingObjectPosition(var4);
303            }
304
305            if (var3 != null)
306            {
307                if (var3.entityHit != null)
308                {
309                    if (var3.entityHit.attackEntityFrom(DamageSource.causeThrownDamage(this, this.angler), 0))
310                    {
311                        this.bobber = var3.entityHit;
312                    }
313                }
314                else
315                {
316                    this.inGround = true;
317                }
318            }
319
320            if (!this.inGround)
321            {
322                this.moveEntity(this.motionX, this.motionY, this.motionZ);
323                float var24 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
324                this.rotationYaw = (float)(Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI);
325
326                for (this.rotationPitch = (float)(Math.atan2(this.motionY, (double)var24) * 180.0D / Math.PI); this.rotationPitch - this.prevRotationPitch < -180.0F; this.prevRotationPitch -= 360.0F)
327                {
328                    ;
329                }
330
331                while (this.rotationPitch - this.prevRotationPitch >= 180.0F)
332                {
333                    this.prevRotationPitch += 360.0F;
334                }
335
336                while (this.rotationYaw - this.prevRotationYaw < -180.0F)
337                {
338                    this.prevRotationYaw -= 360.0F;
339                }
340
341                while (this.rotationYaw - this.prevRotationYaw >= 180.0F)
342                {
343                    this.prevRotationYaw += 360.0F;
344                }
345
346                this.rotationPitch = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * 0.2F;
347                this.rotationYaw = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * 0.2F;
348                float var25 = 0.92F;
349
350                if (this.onGround || this.isCollidedHorizontally)
351                {
352                    var25 = 0.5F;
353                }
354
355                byte var27 = 5;
356                double var26 = 0.0D;
357
358                for (int var29 = 0; var29 < var27; ++var29)
359                {
360                    double var14 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(var29 + 0) / (double)var27 - 0.125D + 0.125D;
361                    double var16 = this.boundingBox.minY + (this.boundingBox.maxY - this.boundingBox.minY) * (double)(var29 + 1) / (double)var27 - 0.125D + 0.125D;
362                    AxisAlignedBB var18 = AxisAlignedBB.getAABBPool().addOrModifyAABBInPool(this.boundingBox.minX, var14, this.boundingBox.minZ, this.boundingBox.maxX, var16, this.boundingBox.maxZ);
363
364                    if (this.worldObj.isAABBInMaterial(var18, Material.water))
365                    {
366                        var26 += 1.0D / (double)var27;
367                    }
368                }
369
370                if (var26 > 0.0D)
371                {
372                    if (this.ticksCatchable > 0)
373                    {
374                        --this.ticksCatchable;
375                    }
376                    else
377                    {
378                        short var28 = 500;
379
380                        if (this.worldObj.canLightningStrikeAt(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY) + 1, MathHelper.floor_double(this.posZ)))
381                        {
382                            var28 = 300;
383                        }
384
385                        if (this.rand.nextInt(var28) == 0)
386                        {
387                            this.ticksCatchable = this.rand.nextInt(30) + 10;
388                            this.motionY -= 0.20000000298023224D;
389                            this.playSound("random.splash", 0.25F, 1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.4F);
390                            float var30 = (float)MathHelper.floor_double(this.boundingBox.minY);
391                            int var15;
392                            float var17;
393                            float var31;
394
395                            for (var15 = 0; (float)var15 < 1.0F + this.width * 20.0F; ++var15)
396                            {
397                                var31 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width;
398                                var17 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width;
399                                this.worldObj.spawnParticle("bubble", this.posX + (double)var31, (double)(var30 + 1.0F), this.posZ + (double)var17, this.motionX, this.motionY - (double)(this.rand.nextFloat() * 0.2F), this.motionZ);
400                            }
401
402                            for (var15 = 0; (float)var15 < 1.0F + this.width * 20.0F; ++var15)
403                            {
404                                var31 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width;
405                                var17 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width;
406                                this.worldObj.spawnParticle("splash", this.posX + (double)var31, (double)(var30 + 1.0F), this.posZ + (double)var17, this.motionX, this.motionY, this.motionZ);
407                            }
408                        }
409                    }
410                }
411
412                if (this.ticksCatchable > 0)
413                {
414                    this.motionY -= (double)(this.rand.nextFloat() * this.rand.nextFloat() * this.rand.nextFloat()) * 0.2D;
415                }
416
417                var13 = var26 * 2.0D - 1.0D;
418                this.motionY += 0.03999999910593033D * var13;
419
420                if (var26 > 0.0D)
421                {
422                    var25 = (float)((double)var25 * 0.9D);
423                    this.motionY *= 0.8D;
424                }
425
426                this.motionX *= (double)var25;
427                this.motionY *= (double)var25;
428                this.motionZ *= (double)var25;
429                this.setPosition(this.posX, this.posY, this.posZ);
430            }
431        }
432    }
433
434    /**
435     * (abstract) Protected helper method to write subclass entity data to NBT.
436     */
437    public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
438    {
439        par1NBTTagCompound.setShort("xTile", (short)this.xTile);
440        par1NBTTagCompound.setShort("yTile", (short)this.yTile);
441        par1NBTTagCompound.setShort("zTile", (short)this.zTile);
442        par1NBTTagCompound.setByte("inTile", (byte)this.inTile);
443        par1NBTTagCompound.setByte("shake", (byte)this.shake);
444        par1NBTTagCompound.setByte("inGround", (byte)(this.inGround ? 1 : 0));
445    }
446
447    /**
448     * (abstract) Protected helper method to read subclass entity data from NBT.
449     */
450    public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
451    {
452        this.xTile = par1NBTTagCompound.getShort("xTile");
453        this.yTile = par1NBTTagCompound.getShort("yTile");
454        this.zTile = par1NBTTagCompound.getShort("zTile");
455        this.inTile = par1NBTTagCompound.getByte("inTile") & 255;
456        this.shake = par1NBTTagCompound.getByte("shake") & 255;
457        this.inGround = par1NBTTagCompound.getByte("inGround") == 1;
458    }
459
460    @SideOnly(Side.CLIENT)
461    public float getShadowSize()
462    {
463        return 0.0F;
464    }
465
466    public int catchFish()
467    {
468        if (this.worldObj.isRemote)
469        {
470            return 0;
471        }
472        else
473        {
474            byte var1 = 0;
475
476            if (this.bobber != null)
477            {
478                double var2 = this.angler.posX - this.posX;
479                double var4 = this.angler.posY - this.posY;
480                double var6 = this.angler.posZ - this.posZ;
481                double var8 = (double)MathHelper.sqrt_double(var2 * var2 + var4 * var4 + var6 * var6);
482                double var10 = 0.1D;
483                this.bobber.motionX += var2 * var10;
484                this.bobber.motionY += var4 * var10 + (double)MathHelper.sqrt_double(var8) * 0.08D;
485                this.bobber.motionZ += var6 * var10;
486                var1 = 3;
487            }
488            else if (this.ticksCatchable > 0)
489            {
490                EntityItem var13 = new EntityItem(this.worldObj, this.posX, this.posY, this.posZ, new ItemStack(Item.fishRaw));
491                double var3 = this.angler.posX - this.posX;
492                double var5 = this.angler.posY - this.posY;
493                double var7 = this.angler.posZ - this.posZ;
494                double var9 = (double)MathHelper.sqrt_double(var3 * var3 + var5 * var5 + var7 * var7);
495                double var11 = 0.1D;
496                var13.motionX = var3 * var11;
497                var13.motionY = var5 * var11 + (double)MathHelper.sqrt_double(var9) * 0.08D;
498                var13.motionZ = var7 * var11;
499                this.worldObj.spawnEntityInWorld(var13);
500                this.angler.addStat(StatList.fishCaughtStat, 1);
501                this.angler.worldObj.spawnEntityInWorld(new EntityXPOrb(this.angler.worldObj, this.angler.posX, this.angler.posY + 0.5D, this.angler.posZ + 0.5D, this.rand.nextInt(6) + 1));
502                var1 = 1;
503            }
504
505            if (this.inGround)
506            {
507                var1 = 2;
508            }
509
510            this.setDead();
511            this.angler.fishEntity = null;
512            return var1;
513        }
514    }
515
516    /**
517     * Will get destroyed next tick.
518     */
519    public void setDead()
520    {
521        super.setDead();
522
523        if (this.angler != null)
524        {
525            this.angler.fishEntity = null;
526        }
527    }
528}