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 }