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 }