package joshie.harvest.npcs.entity.ai;
import joshie.harvest.api.HFApi;
import joshie.harvest.api.buildings.BuildingLocation;
import joshie.harvest.api.calendar.CalendarDate;
import joshie.harvest.calendar.CalendarHelper;
import joshie.harvest.npcs.NPCHelper;
import joshie.harvest.npcs.entity.EntityNPCHuman;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.ai.RandomPositionGenerator;
import net.minecraft.pathfinding.Path;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import javax.annotation.Nullable;
public class EntityAISchedule extends EntityAIBase {
private final EntityNPCHuman npc;
private double distanceRequired;
private int ticksBeforeTeleport;
private BlockPos blockTarget;
private BlockPos prevTarget;
private int teleportTimer;
private int scheduleTimer;
public EntityAISchedule(EntityNPCHuman npc) {
this.npc = npc;
this.setMutexBits(1);
}
@Nullable
private BuildingLocation getBuildingTarget(CalendarDate date) {
return npc.getNPC().getScheduler().getTarget(npc.worldObj, npc, date.getSeason(), date.getWeekday(), CalendarHelper.getTime(npc.worldObj));
}
@Override
public boolean shouldExecute() {
if (npc.getNPC() == null) return false;
updateTarget(); //Called here as need to check for new targets
return blockTarget == null || (npc.getDistanceSq(blockTarget) > distanceRequired);
}
@Override
public boolean continueExecuting() {
return blockTarget != null && !npc.isTalking();
}
private void updateTarget() {
CalendarDate date = HFApi.calendar.getDate(npc.worldObj);
BuildingLocation location = getBuildingTarget(date);
if (location != null) {
distanceRequired = location.distance;
ticksBeforeTeleport = location.updatesBeforeTeleport;
blockTarget = NPCHelper.getCoordinatesForLocation(npc, location);
if (blockTarget != null) blockTarget = blockTarget.down();
}
}
@Nullable
private Path getPathToTarget() {
Path path = npc.getNavigator().getPathToPos(blockTarget);
if (path != null) return path;
else {
//Grab a random block towards the target
Vec3d vec = RandomPositionGenerator.findRandomTargetBlockTowards(npc, 16, 7, new Vec3d((double) blockTarget.getX() + 0.5D, (double) blockTarget.getY(), (double) blockTarget.getZ() + 0.5D));
if (vec != null) {
return npc.getNavigator().getPathToPos(new BlockPos(vec));
} else return null;
}
}
@Nullable
private Path getPathAwayFromTarget() {
Vec3d vec = RandomPositionGenerator.findRandomTargetBlockAwayFrom(npc, (int) distanceRequired / 2, 3, new Vec3d((double) blockTarget.getX() + 0.5D, (double) blockTarget.getY(), (double) blockTarget.getZ() + 0.5D));
if (vec != null) {
blockTarget = new BlockPos(vec); //Update the target, so we don't teleport back
return npc.getNavigator().getPathToPos(blockTarget);
} else return null;
}
private boolean shouldTeleport() {
if (!blockTarget.equals(prevTarget)) teleportTimer = 0;
else teleportTimer++; //Update the teleport timer if the target is the same
prevTarget = blockTarget; //Update the prevTarget
return teleportTimer >= ticksBeforeTeleport;
}
@Override
public void updateTask() {
if (scheduleTimer %200 == 0) updateTarget();
if (blockTarget != null) {
//If we're too far away from the target, based on the location requirements then
if (npc.getDistanceSq(blockTarget) > distanceRequired) {
if (scheduleTimer %100 == 0) {
if (shouldTeleport()) {
teleportTimer = 0; //Reset the teleport timer
npc.attemptTeleport(blockTarget.getX() + 0.5D, blockTarget.getY() + 1D, blockTarget.getZ() + 0.5D);
} else {
Path path = getPathToTarget();
if (path != null) {
npc.getNavigator().setPath(path, 0.6F);
}
}
}
} //else if (distanceRequired == 1) npc.getNavigator().clearPathEntity();
else if (distanceRequired > 1 && scheduleTimer % 300 == 0) { //If the location is larger than 0, allow wandering
Path path = getPathAwayFromTarget();
if (path != null) {
npc.getNavigator().setPath(path, 0.6F);
}
}
}
scheduleTimer++;
}
}