package crazypants.enderzoo.entity.ai; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IRangedAttackMob; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.util.math.MathHelper; public class EntityAIRangedAttack extends EntityAIBase { private final EntityLiving entityHost; private final IRangedAttackMob rangedAttackEntityHost; private EntityLivingBase attackTarget; private int timeUntilNextAttack; private double entityMoveSpeed; private int timeTargetVisible; private int timeTargetHidden; private int minRangedAttackTime; private int maxRangedAttackTime; private float attackRange; private float attackRangeSq; public EntityAIRangedAttack(IRangedAttackMob host, double moveSpeed, int timeBetweenAttacks, float attackRange) { this(host, moveSpeed, timeBetweenAttacks, timeBetweenAttacks, attackRange); } public EntityAIRangedAttack(IRangedAttackMob host, double moveSpeed, int minTimeBetweenAttacks, int maxTimeBetweenAttacks, float range) { timeUntilNextAttack = -1; rangedAttackEntityHost = host; entityHost = (EntityLiving) host; entityMoveSpeed = moveSpeed; minRangedAttackTime = minTimeBetweenAttacks; maxRangedAttackTime = maxTimeBetweenAttacks; attackRange = range; attackRangeSq = attackRange * attackRange; setMutexBits(3); } @Override public boolean shouldExecute() { EntityLivingBase target = entityHost.getAttackTarget(); if (target == null) { return false; } attackTarget = target; return true; } public EntityLivingBase getAttackTarget() { return attackTarget; } @Override public boolean shouldContinueExecuting() { return shouldExecute() || !entityHost.getNavigator().noPath(); } protected double getTargetDistance() { IAttributeInstance iattributeinstance = entityHost.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE); return iattributeinstance == null ? 16.0D : iattributeinstance.getAttributeValue(); } @Override public void resetTask() { attackTarget = null; timeTargetVisible = 0; timeUntilNextAttack = -1; } @Override public void updateTask() { double distToTargetSq = entityHost.getDistanceSq(attackTarget.posX, attackTarget.getEntityBoundingBox().minY, attackTarget.posZ); boolean canSee = entityHost.getEntitySenses().canSee(attackTarget); if (canSee) { ++timeTargetVisible; } else { timeTargetVisible = 0; } if (distToTargetSq <= attackRangeSq && timeTargetVisible >= 20) { entityHost.getNavigator().clearPathEntity(); } else if (timeTargetHidden < 100) { entityHost.getNavigator().tryMoveToEntityLiving(attackTarget, entityMoveSpeed); } entityHost.getLookHelper().setLookPositionWithEntity(attackTarget, 30.0F, 30.0F); if (--timeUntilNextAttack <= 0) { if (distToTargetSq > attackRangeSq || !canSee) { return; } float rangeRatio = MathHelper.sqrt(distToTargetSq) / attackRange; if (rangeRatio < 0.1F) { rangeRatio = 0.1F; } else if (rangeRatio > 1.0F) { rangeRatio = 1.0F; } rangedAttackEntityHost.attackEntityWithRangedAttack(attackTarget, rangeRatio); timeUntilNextAttack = MathHelper.floor(rangeRatio * (maxRangedAttackTime - minRangedAttackTime) + minRangedAttackTime); } else if (timeUntilNextAttack < 0) { entityHost.setAttackTarget(attackTarget); float rangeRatio = MathHelper.sqrt(distToTargetSq) / attackRange; timeUntilNextAttack = MathHelper.floor(rangeRatio * (maxRangedAttackTime - minRangedAttackTime) + minRangedAttackTime); } } }