001    package net.minecraft.src;
002    
003    public class EntityAIArrowAttack extends EntityAIBase
004    {
005        World worldObj;
006    
007        /** The entity the AI instance has been applied to */
008        EntityLiving entityHost;
009        EntityLiving attackTarget;
010    
011        /**
012         * A decrementing tick that spawns a ranged attack once this value reaches 0. It is then set back to the
013         * maxRangedAttackTime.
014         */
015        int rangedAttackTime = 0;
016        float entityMoveSpeed;
017        int field_75318_f = 0;
018    
019        /**
020         * The ID of this ranged attack AI. This chooses which entity is to be used as a ranged attack.
021         */
022        int rangedAttackID;
023    
024        /**
025         * The maximum time the AI has to wait before peforming another ranged attack.
026         */
027        int maxRangedAttackTime;
028    
029        public EntityAIArrowAttack(EntityLiving par1EntityLiving, float par2, int par3, int par4)
030        {
031            this.entityHost = par1EntityLiving;
032            this.worldObj = par1EntityLiving.worldObj;
033            this.entityMoveSpeed = par2;
034            this.rangedAttackID = par3;
035            this.maxRangedAttackTime = par4;
036            this.setMutexBits(3);
037        }
038    
039        /**
040         * Returns whether the EntityAIBase should begin execution.
041         */
042        public boolean shouldExecute()
043        {
044            EntityLiving var1 = this.entityHost.getAttackTarget();
045    
046            if (var1 == null)
047            {
048                return false;
049            }
050            else
051            {
052                this.attackTarget = var1;
053                return true;
054            }
055        }
056    
057        /**
058         * Returns whether an in-progress EntityAIBase should continue executing
059         */
060        public boolean continueExecuting()
061        {
062            return this.shouldExecute() || !this.entityHost.getNavigator().noPath();
063        }
064    
065        /**
066         * Resets the task
067         */
068        public void resetTask()
069        {
070            this.attackTarget = null;
071        }
072    
073        /**
074         * Updates the task
075         */
076        public void updateTask()
077        {
078            double var1 = 100.0D;
079            double var3 = this.entityHost.getDistanceSq(this.attackTarget.posX, this.attackTarget.boundingBox.minY, this.attackTarget.posZ);
080            boolean var5 = this.entityHost.getEntitySenses().canSee(this.attackTarget);
081    
082            if (var5)
083            {
084                ++this.field_75318_f;
085            }
086            else
087            {
088                this.field_75318_f = 0;
089            }
090    
091            if (var3 <= var1 && this.field_75318_f >= 20)
092            {
093                this.entityHost.getNavigator().clearPathEntity();
094            }
095            else
096            {
097                this.entityHost.getNavigator().tryMoveToEntityLiving(this.attackTarget, this.entityMoveSpeed);
098            }
099    
100            this.entityHost.getLookHelper().setLookPositionWithEntity(this.attackTarget, 30.0F, 30.0F);
101            this.rangedAttackTime = Math.max(this.rangedAttackTime - 1, 0);
102    
103            if (this.rangedAttackTime <= 0)
104            {
105                if (var3 <= var1 && var5)
106                {
107                    this.doRangedAttack();
108                    this.rangedAttackTime = this.maxRangedAttackTime;
109                }
110            }
111        }
112    
113        /**
114         * Performs a ranged attack according to the AI's rangedAttackID.
115         */
116        private void doRangedAttack()
117        {
118            if (this.rangedAttackID == 1)
119            {
120                EntityArrow var1 = new EntityArrow(this.worldObj, this.entityHost, this.attackTarget, 1.6F, 12.0F);
121                this.worldObj.playSoundAtEntity(this.entityHost, "random.bow", 1.0F, 1.0F / (this.entityHost.getRNG().nextFloat() * 0.4F + 0.8F));
122                this.worldObj.spawnEntityInWorld(var1);
123            }
124            else if (this.rangedAttackID == 2)
125            {
126                EntitySnowball var9 = new EntitySnowball(this.worldObj, this.entityHost);
127                double var2 = this.attackTarget.posX - this.entityHost.posX;
128                double var4 = this.attackTarget.posY + (double)this.attackTarget.getEyeHeight() - 1.100000023841858D - var9.posY;
129                double var6 = this.attackTarget.posZ - this.entityHost.posZ;
130                float var8 = MathHelper.sqrt_double(var2 * var2 + var6 * var6) * 0.2F;
131                var9.setThrowableHeading(var2, var4 + (double)var8, var6, 1.6F, 12.0F);
132                this.worldObj.playSoundAtEntity(this.entityHost, "random.bow", 1.0F, 1.0F / (this.entityHost.getRNG().nextFloat() * 0.4F + 0.8F));
133                this.worldObj.spawnEntityInWorld(var9);
134            }
135        }
136    }