001 package net.minecraft.entity.ai;
002
003 import net.minecraft.entity.EntityLiving;
004 import net.minecraft.entity.IRangedAttackMob;
005
006 public class EntityAIArrowAttack extends EntityAIBase
007 {
008 /** The entity the AI instance has been applied to */
009 private final EntityLiving entityHost;
010
011 /**
012 * The entity (as a RangedAttackMob) the AI instance has been applied to.
013 */
014 private final IRangedAttackMob rangedAttackEntityHost;
015 private EntityLiving attackTarget;
016
017 /**
018 * A decrementing tick that spawns a ranged attack once this value reaches 0. It is then set back to the
019 * maxRangedAttackTime.
020 */
021 private int rangedAttackTime = 0;
022 private float entityMoveSpeed;
023 private int field_75318_f = 0;
024
025 /**
026 * The maximum time the AI has to wait before peforming another ranged attack.
027 */
028 private int maxRangedAttackTime;
029 private float field_82642_h;
030
031 public EntityAIArrowAttack(IRangedAttackMob par1IRangedAttackMob, float par2, int par3, float par4)
032 {
033 if (!(par1IRangedAttackMob instanceof EntityLiving))
034 {
035 throw new IllegalArgumentException("ArrowAttackGoal requires Mob implements RangedAttackMob");
036 }
037 else
038 {
039 this.rangedAttackEntityHost = par1IRangedAttackMob;
040 this.entityHost = (EntityLiving)par1IRangedAttackMob;
041 this.entityMoveSpeed = par2;
042 this.maxRangedAttackTime = par3;
043 this.field_82642_h = par4 * par4;
044 this.rangedAttackTime = par3 / 2;
045 this.setMutexBits(3);
046 }
047 }
048
049 /**
050 * Returns whether the EntityAIBase should begin execution.
051 */
052 public boolean shouldExecute()
053 {
054 EntityLiving var1 = this.entityHost.getAttackTarget();
055
056 if (var1 == null)
057 {
058 return false;
059 }
060 else
061 {
062 this.attackTarget = var1;
063 return true;
064 }
065 }
066
067 /**
068 * Returns whether an in-progress EntityAIBase should continue executing
069 */
070 public boolean continueExecuting()
071 {
072 return this.shouldExecute() || !this.entityHost.getNavigator().noPath();
073 }
074
075 /**
076 * Resets the task
077 */
078 public void resetTask()
079 {
080 this.attackTarget = null;
081 this.field_75318_f = 0;
082 this.rangedAttackTime = this.maxRangedAttackTime / 2;
083 }
084
085 /**
086 * Updates the task
087 */
088 public void updateTask()
089 {
090 double var1 = this.entityHost.getDistanceSq(this.attackTarget.posX, this.attackTarget.boundingBox.minY, this.attackTarget.posZ);
091 boolean var3 = this.entityHost.getEntitySenses().canSee(this.attackTarget);
092
093 if (var3)
094 {
095 ++this.field_75318_f;
096 }
097 else
098 {
099 this.field_75318_f = 0;
100 }
101
102 if (var1 <= (double)this.field_82642_h && this.field_75318_f >= 20)
103 {
104 this.entityHost.getNavigator().clearPathEntity();
105 }
106 else
107 {
108 this.entityHost.getNavigator().tryMoveToEntityLiving(this.attackTarget, this.entityMoveSpeed);
109 }
110
111 this.entityHost.getLookHelper().setLookPositionWithEntity(this.attackTarget, 30.0F, 30.0F);
112 this.rangedAttackTime = Math.max(this.rangedAttackTime - 1, 0);
113
114 if (this.rangedAttackTime <= 0)
115 {
116 if (var1 <= (double)this.field_82642_h && var3)
117 {
118 this.rangedAttackEntityHost.attackEntityWithRangedAttack(this.attackTarget);
119 this.rangedAttackTime = this.maxRangedAttackTime;
120 }
121 }
122 }
123 }