package mhfc.net.common.ai.entity.boss.deviljho;
import mhfc.net.common.ai.ActionAdapter;
import mhfc.net.common.ai.general.AIUtils;
import mhfc.net.common.ai.general.AIUtils.IDamageCalculator;
import mhfc.net.common.entity.monster.EntityDeviljho;
import mhfc.net.common.util.world.WorldHelper;
import net.minecraft.entity.Entity;
import net.minecraft.util.Vec3;
public class MoveToTarget extends ActionAdapter<EntityDeviljho> {
private static final int MOVEMENT_START = 5;
private static final int MOVEMENT_FINISH = 40;
private static final int AI_END = 40;
private static final float TURN_RATE_INITIAL = 20.5f;
private static final float TURN_RATE_DURING_RUN = 20.05f;
private static final float MAX_RUN_DISTANCE = 20f;
private static final int MAX_RUN_FRAMES = 200;
private static final double RUN_SPEED = 0.6;
private static final double STOP_SPEED = 0.4;
private static final IDamageCalculator damageCalc = AIUtils.defaultDamageCalc(125f, 50f, 9999999f);
private static final double MAX_DIST = 3f;
private static enum PastEntityEnum {
NOT_PASSED,
PASSED,
LOOP_FINISHED,
TURNING;
}
private static enum AttackPhase {
START(false) {
@Override
public void onPhaseStart(MoveToTarget attk) {
EntityDeviljho monster = attk.getEntity();
monster.motionX = monster.motionY = monster.motionZ = 0f;
monster.getTurnHelper().updateTurnSpeed(TURN_RATE_INITIAL);
attk.getEntity().getTurnHelper().updateTargetPoint(attk.target);
}
@Override
public void update(MoveToTarget attk) {
attk.getEntity().getTurnHelper().forceUpdate();
}
@Override
public AttackPhase next(MoveToTarget attk) {
if (attk.target == null) {
return STOPPED;
}
if (attk.getCurrentFrame() < MOVEMENT_START) {
return START;
}
return RUNNING;
}
},
RUNNING(true) {
@Override
public void onPhaseStart(MoveToTarget attk) {
attk.getEntity().getTurnHelper().updateTurnSpeed(TURN_RATE_DURING_RUN);
attk.framesRunning = 0;
}
@Override
public void update(MoveToTarget attk) {
EntityDeviljho monster = attk.getEntity();
Vec3 mobPos = Vec3.createVectorHelper(monster.posX, monster.posY, monster.posZ);
Vec3 vecToTarget = mobPos.subtract(WorldHelper.getEntityPositionVector(attk.target));
monster.getTurnHelper().updateTargetPoint(attk.target);
monster.moveForward(RUN_SPEED, true);
Vec3 look = monster.getLookVec();
boolean tarBeh = vecToTarget.normalize().dotProduct(look) < 0;
boolean ranLongEnough = attk.runStartPoint.subtract(mobPos).lengthVector() > MAX_RUN_DISTANCE
|| attk.framesRunning > MAX_RUN_FRAMES;
if ((tarBeh || ranLongEnough) && attk.hasPassed == PastEntityEnum.NOT_PASSED) {
attk.hasPassed = PastEntityEnum.PASSED;
}
}
@Override
public AttackPhase next(MoveToTarget attk) {
if (attk.hasPassed == PastEntityEnum.LOOP_FINISHED) {
return STOPPING;
}
return RUNNING;
}
@Override
public int nextFrame(MoveToTarget attk, int curr) {
attk.framesRunning++;
int looping = MOVEMENT_FINISH - MOVEMENT_START;
if (attk.hasPassed == PastEntityEnum.PASSED && (curr + 1 >= MOVEMENT_FINISH)) {
attk.hasPassed = PastEntityEnum.LOOP_FINISHED;
}
return MOVEMENT_START + (curr + 1 - MOVEMENT_START) % looping;
}
},
STOPPING(true) {
@Override
public void update(MoveToTarget attk) {
EntityDeviljho e = attk.getEntity();
e.moveForward(STOP_SPEED, false);
}
@Override
public AttackPhase next(MoveToTarget attk) {
if (AI_END < attk.getCurrentFrame()) {
return STOPPED;
}
return STOPPING;
}
},
STOPPED(false) {
@Override
public void onPhaseStart(MoveToTarget attk) {
Entity entity = attk.getEntity();
entity.motionX = entity.motionY = entity.motionZ = 0f;
}
};
public final boolean isDamaging;
private AttackPhase(boolean isDamaging) {
this.isDamaging = isDamaging;
}
public void onPhaseStart(MoveToTarget attk) {}
public void update(MoveToTarget attk) {}
public AttackPhase next(MoveToTarget attk) {
return this;
}
public int nextFrame(MoveToTarget attk, int curr) {
return ++curr;
}
}
private AttackPhase currentPhase;
private PastEntityEnum hasPassed;
private Vec3 runStartPoint;
private int framesRunning;
@SuppressWarnings("unused")
private int runCycles;
public MoveToTarget() {
setAnimation("mhfc:models/Deviljho/DeviljhoWalk.mcanm");
}
@Override
public float getWeight() {
EntityDeviljho monster = this.getEntity();
target = monster.getAttackTarget();
if (target == null) {
return DONT_SELECT;
}
Vec3 toTarget = WorldHelper.getVectorToTarget(monster, target);
double dist = toTarget.lengthVector();
if (dist < MAX_DIST) {
return DONT_SELECT;
}
return (float) Math.log(dist / 5f + 1); // More likely the further away
}
@Override
public void beginExecution() {
EntityDeviljho mob = getEntity();
target = mob.getAttackTarget();
mob.playSound("mhfc:deviljho.roar", 1.0F, 1.0F);
currentPhase = AttackPhase.START;
hasPassed = PastEntityEnum.NOT_PASSED;
runCycles = 0;
framesRunning = 0;
currentPhase.onPhaseStart(this);
runStartPoint = Vec3.createVectorHelper(mob.posX, mob.posY, mob.posZ);
}
@Override
public void update() {
currentPhase.update(this);
if (currentPhase.isDamaging) {
AIUtils.damageCollidingEntities(getEntity(), damageCalc);
}
AttackPhase nextPhase = currentPhase.next(this);
if (currentPhase != nextPhase) {
nextPhase.onPhaseStart(this);
currentPhase = nextPhase;
}
}
@Override
public boolean shouldContinue() { // To determine if to cancel
return this.currentPhase != AttackPhase.STOPPED;
}
@Override
public void finishExecution() { // When finished
}
@Override
public byte mutexBits() { // Well known mutex bits
return 1;
}
@Override
public int setToNextFrame(int frame) { // For the animation
return super.setToNextFrame(currentPhase.nextFrame(this, frame)); // Notify
// the
// adapter
}
}