    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    }