mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 21:17:32 +00:00
171 lines
6.3 KiB
Java
171 lines
6.3 KiB
Java
package noppes.npcs.ai;
|
|
|
|
import net.minecraft.entity.EntityLivingBase;
|
|
import net.minecraft.entity.IRangedAttackMob;
|
|
import net.minecraft.entity.ai.EntityAIBase;
|
|
import net.minecraft.util.MathHelper;
|
|
import noppes.npcs.constants.AiMutex;
|
|
import noppes.npcs.constants.EnumAnimation;
|
|
import noppes.npcs.constants.EnumNavType;
|
|
import noppes.npcs.entity.EntityNPCInterface;
|
|
|
|
public class EntityAIRangedAttack extends EntityAIBase {
|
|
/**
|
|
* The entity the AI instance has been applied to
|
|
*/
|
|
private final EntityNPCInterface entityHost;
|
|
|
|
/**
|
|
* The entity (as a RangedAttackMob) the AI instance has been applied to.
|
|
*/
|
|
private final IRangedAttackMob rangedAttackEntityHost;
|
|
private EntityLivingBase attackTarget;
|
|
|
|
/**
|
|
* A decrementing tick that spawns a ranged attack once this value reaches 0. It is then set back to the
|
|
* maxRangedAttackTime.
|
|
*/
|
|
private int rangedAttackTime = 0;
|
|
private int field_75318_f = 0;
|
|
private int field_70846_g = 0;
|
|
private int attackTick = 0;
|
|
private boolean hasFired = false;
|
|
private boolean navOverride = false;
|
|
private boolean isShooting = false;
|
|
|
|
public EntityAIRangedAttack(IRangedAttackMob par1IRangedAttackMob) {
|
|
if (!(par1IRangedAttackMob instanceof EntityLivingBase)) {
|
|
throw new IllegalArgumentException("ArrowAttackGoal requires Mob implements RangedAttackMob");
|
|
} else {
|
|
this.rangedAttackEntityHost = par1IRangedAttackMob;
|
|
this.entityHost = (EntityNPCInterface) par1IRangedAttackMob;
|
|
this.rangedAttackTime = this.entityHost.stats.minDelay / 2;
|
|
this.setMutexBits(this.navOverride ? AiMutex.PATHING : AiMutex.LOOK + AiMutex.PASSIVE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether the EntityAIBase should begin execution.
|
|
*/
|
|
public boolean shouldExecute() {
|
|
EntityLivingBase var1 = this.entityHost.getAttackTarget();
|
|
|
|
if (var1 == null || !var1.isEntityAlive()) {
|
|
isShooting = false;
|
|
return false;
|
|
}
|
|
|
|
if (entityHost.getDistanceToEntity(var1) > entityHost.stats.aggroRange) {
|
|
isShooting = false;
|
|
return false;
|
|
}
|
|
|
|
if (this.entityHost.inventory.getProjectile() == null) {
|
|
isShooting = false;
|
|
return false;
|
|
}
|
|
|
|
double var2 = this.entityHost.getDistanceSq(var1.posX, var1.boundingBox.minY, var1.posZ);
|
|
double var3 = this.entityHost.ais.distanceToMelee * this.entityHost.ais.distanceToMelee;
|
|
|
|
if (this.entityHost.ais.useRangeMelee >= 1 && var2 <= var3) {
|
|
isShooting = false;
|
|
return false;
|
|
} else {
|
|
this.attackTarget = var1;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether an in-progress EntityAIBase should continue executing
|
|
*/
|
|
public boolean continueExecuting() {
|
|
return this.shouldExecute() || !this.entityHost.getNavigator().noPath();
|
|
}
|
|
|
|
/**
|
|
* Resets the task
|
|
*/
|
|
public void resetTask() {
|
|
this.attackTarget = null;
|
|
this.entityHost.setAttackTarget(null);
|
|
this.entityHost.getNavigator().clearPathEntity();
|
|
this.field_75318_f = 0;
|
|
this.hasFired = false;
|
|
this.rangedAttackTime = this.entityHost.stats.minDelay / 2;
|
|
}
|
|
|
|
/**
|
|
* Updates the task
|
|
*/
|
|
public void updateTask() {
|
|
this.entityHost.getLookHelper().setLookPositionWithEntity(this.attackTarget, 30.0F, 30.0F);
|
|
double var1 = this.entityHost.getDistanceSq(this.attackTarget.posX, this.attackTarget.boundingBox.minY, this.attackTarget.posZ);
|
|
float field_82642_h = this.entityHost.stats.rangedRange * this.entityHost.stats.rangedRange;
|
|
|
|
if (!navOverride && this.entityHost.ais.directLOS) {
|
|
if (this.entityHost.getEntitySenses().canSee(this.attackTarget)) {
|
|
++this.field_75318_f;
|
|
} else {
|
|
this.field_75318_f = 0;
|
|
}
|
|
int v = this.entityHost.ais.tacticalVariant == EnumNavType.Default ? 20 : 5;
|
|
if (var1 <= (double) field_82642_h && this.field_75318_f >= v) {
|
|
this.entityHost.getNavigator().clearPathEntity();
|
|
} else {
|
|
this.entityHost.getNavigator().tryMoveToEntityLiving(this.attackTarget, 1.0D);
|
|
}
|
|
}
|
|
|
|
this.rangedAttackTime = Math.max(this.rangedAttackTime - 1, 0);
|
|
|
|
if (this.rangedAttackTime <= 0) {
|
|
if (var1 <= (double) field_82642_h && (this.entityHost.getEntitySenses().canSee(this.attackTarget) || this.entityHost.ais.canFireIndirect == 2)) {
|
|
if (this.field_70846_g == 0) {
|
|
this.entityHost.stats.playBurstSound = true;
|
|
}
|
|
if (this.field_70846_g++ <= this.entityHost.stats.burstCount) {
|
|
this.rangedAttackTime = this.entityHost.stats.fireRate;
|
|
this.isShooting = true;
|
|
} else {
|
|
this.field_70846_g = 0;
|
|
this.hasFired = true;
|
|
this.rangedAttackTime = (this.entityHost.stats.maxDelay - MathHelper.floor_float(this.entityHost.getRNG().nextFloat() * (this.entityHost.stats.maxDelay - this.entityHost.stats.minDelay)));
|
|
this.isShooting = false;
|
|
}
|
|
|
|
if (this.field_70846_g > 1) {
|
|
boolean indirect = false;
|
|
|
|
switch (this.entityHost.ais.canFireIndirect) {
|
|
case 1:
|
|
indirect = var1 > (double) field_82642_h / 2;
|
|
break;
|
|
case 2:
|
|
indirect = !this.entityHost.getEntitySenses().canSee(this.attackTarget);
|
|
}
|
|
|
|
this.rangedAttackEntityHost.attackEntityWithRangedAttack(this.attackTarget, indirect ? 1 : 0);
|
|
if (this.entityHost.currentAnimation != EnumAnimation.AIMING) {
|
|
this.entityHost.swingItem();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean hasFired() {
|
|
return this.hasFired;
|
|
}
|
|
|
|
public boolean isShooting() {
|
|
return this.isShooting;
|
|
}
|
|
|
|
public void navOverride(boolean nav) {
|
|
this.navOverride = nav;
|
|
this.setMutexBits(this.navOverride ? AiMutex.PATHING : AiMutex.LOOK + AiMutex.PASSIVE);
|
|
}
|
|
}
|