/*
* This file is part of Matter Overdrive
* Copyright (c) 2015., Simeon Radivoev, All rights reserved.
*
* Matter Overdrive is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Matter Overdrive is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Matter Overdrive. If not, see <http://www.gnu.org/licenses>.
*/
package matteroverdrive.entity.ai;
import matteroverdrive.api.entity.IRangedEnergyWeaponAttackMob;
import matteroverdrive.items.weapon.EnergyWeapon;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.item.ItemStack;
import net.minecraft.pathfinding.PathEntity;
import net.minecraft.util.Vec3;
/**
* Created by Simeon on 11/15/2015.
*/
public class EntityAIPhaserBoltAttack extends EntityAIBase
{
/** The entity the AI instance has been applied to */
private final EntityLiving entityHost;
/** The entity (as a RangedAttackMob) the AI instance has been applied to. */
private final IRangedEnergyWeaponAttackMob rangedAttackEntityHost;
private EntityLivingBase attackTarget;
private Vec3 lastKnownShootLocation;
/**
* A decrementing tick that spawns a ranged attack once this value reaches 0. It is then set back to the
* maxRangedAttackDelay.
*/
private int rangedAttackDelayTime;
private double entityMoveSpeed;
private int pathRetryTimer;
private int shootPatienceTime;
/** The maximum time the AI has to wait before peforming another ranged attack. */
private int maxRangedAttackDelay;
private float maxChaseDistance;
private float maxChaseDistanceSq;
private PathEntity lastChasePath;
public EntityAIPhaserBoltAttack(IRangedEnergyWeaponAttackMob rangedAttackEntityHost, double entityMoveSpeed, int maxRangedAttackDelay, float maxChaseDistance)
{
this(rangedAttackEntityHost, entityMoveSpeed, maxRangedAttackDelay, maxRangedAttackDelay, maxChaseDistance);
}
public EntityAIPhaserBoltAttack(IRangedEnergyWeaponAttackMob rangedAttackEntityHost, double entityMoveSpeed, int p_i1650_4_, int maxRangedAttackDelay, float maxChaseDistance)
{
this.rangedAttackDelayTime = -1;
if (!(rangedAttackEntityHost instanceof EntityLivingBase))
{
throw new IllegalArgumentException("EntityAIPhaserBoltAttack requires Mob implements IRangedEnergyWeaponAttackMob");
}
else
{
this.rangedAttackEntityHost = rangedAttackEntityHost;
this.entityHost = (EntityLiving)rangedAttackEntityHost;
this.entityMoveSpeed = entityMoveSpeed;
this.maxRangedAttackDelay = maxRangedAttackDelay;
this.maxChaseDistance = maxChaseDistance;
this.maxChaseDistanceSq = maxChaseDistance * maxChaseDistance;
this.setMutexBits(3);
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
EntityLivingBase entitylivingbase = this.entityHost.getAttackTarget();
if (entitylivingbase == null)
{
return false;
}
else if (!entitylivingbase.isDead)
{
this.attackTarget = entitylivingbase;
return true;
}
return false;
}
/**
* 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.pathRetryTimer = 0;
this.rangedAttackDelayTime = -1;
this.shootPatienceTime = 0;
}
/**
* Updates the task
*/
public void updateTask()
{
double distanceToTargetSq = this.entityHost.getDistanceSq(this.attackTarget.posX, this.attackTarget.boundingBox.minY, this.attackTarget.posZ);
boolean canSee = this.entityHost.getEntitySenses().canSee(this.attackTarget);
if (canSee)
{
lastKnownShootLocation = Vec3.createVectorHelper(attackTarget.prevPosX,attackTarget.prevPosY,attackTarget.prevPosZ);
shootPatienceTime = 60;
++this.pathRetryTimer;
}
else
{
this.pathRetryTimer = 0;
}
manageMovingToLastKnowMoveLocation(distanceToTargetSq);
if (shootPatienceTime == 0)
{
lastKnownShootLocation = null;
}
if (lastKnownShootLocation != null)
{
manageShooting(canSee,distanceToTargetSq);
shootPatienceTime--;
}
else
{
this.entityHost.getLookHelper().setLookPosition(attackTarget.posX, attackTarget.posY + attackTarget.getEyeHeight(), attackTarget.posZ, 30.0F, 30.0F);
}
}
private void manageMovingToLastKnowMoveLocation(double distanceToTargetSq)
{
if (distanceToTargetSq <= (double)this.maxChaseDistanceSq && this.pathRetryTimer >= 20)
{
if(this.entityHost.getNavigator().getPath() != null && this.entityHost.getNavigator().getPath().equals(lastChasePath))
this.entityHost.getNavigator().clearPathEntity();
}else if (this.entityHost.getNavigator().noPath())
{
lastChasePath = this.entityHost.getNavigator().getPathToEntityLiving(attackTarget);
this.entityHost.getNavigator().setPath(lastChasePath,this.entityMoveSpeed);
}
}
private void manageShooting(boolean canSeeTarget,double distanceToTargetSq)
{
this.entityHost.getLookHelper().setLookPosition(this.lastKnownShootLocation.xCoord, this.lastKnownShootLocation.yCoord + attackTarget.getEyeHeight(), this.lastKnownShootLocation.zCoord, 30.0F, 30.0F);
float distancePercentage;
ItemStack weapon = rangedAttackEntityHost.getWeapon();
if (this.rangedAttackDelayTime == 0 && weapon != null && weapon.getItem() instanceof EnergyWeapon && ((EnergyWeapon) weapon.getItem()).canFire(weapon,entityHost.worldObj,entityHost))
{
if (distanceToTargetSq > (double)this.maxChaseDistanceSq )
{
return;
}
this.rangedAttackEntityHost.attackEntityWithRangedAttack(this.attackTarget, lastKnownShootLocation,canSeeTarget);
this.rangedAttackDelayTime = this.maxRangedAttackDelay;
}
else if (this.rangedAttackDelayTime < 0)
{
this.rangedAttackDelayTime = this.maxRangedAttackDelay;
}else if (this.rangedAttackDelayTime > 0)
{
this.rangedAttackDelayTime--;
}
}
public void setMaxRangedAttackDelay(int time)
{
this.maxRangedAttackDelay = time;
}
public void setMaxChaseDistance(int maxChaseDistance)
{
this.maxChaseDistance = maxChaseDistance;
this.maxChaseDistanceSq = maxChaseDistance*maxChaseDistance;
}
}