package data.scripts.ai;
import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.combat.*;
import com.fs.starfarer.api.combat.CollisionClass;
import com.fs.starfarer.api.combat.CombatEngineAPI;
import com.fs.starfarer.api.combat.CombatEntityAPI;
import com.fs.starfarer.api.combat.GuidedMissileAI;
import com.fs.starfarer.api.combat.MissileAIPlugin;
import com.fs.starfarer.api.combat.MissileAPI;
import com.fs.starfarer.api.combat.ShipAPI;
import com.fs.starfarer.api.combat.ShipCommand;
import org.lazywizard.lazylib.MathUtils;
import java.awt.Color;
import java.util.List;
import org.lazywizard.lazylib.VectorUtils;
import org.lazywizard.lazylib.combat.AIUtils;
import org.lwjgl.util.vector.Vector2f;
import com.fs.starfarer.api.util.Misc;
import com.fs.starfarer.api.util.WeightedRandomPicker;
import data.scripts.util.MagicLensFlare;
import org.lazywizard.lazylib.MathUtils;
import org.lazywizard.lazylib.combat.AIUtils;
public class SCQ_LongbowMissileAI implements MissileAIPlugin, GuidedMissileAI {
private static final Color JITTER_COLOR = new Color(143, 169,255,75);
private static final Color JITTER_UNDER_COLOR = new Color(123, 144,255,155);
private CombatEngineAPI engine;
public WeaponAPI weapon;
private List<MissileAPI> missiles;
private MissileAPI missile;
private ShipAPI ship,
launchingShip;
private CombatEntityAPI target;
private Vector2f targetLocation;
private boolean runOnce = false;
private String missileId = "LNC_waver_CN_mrm",
missileTeleporterId = "LNC_longbow_waver_mrm_teleporter",
teleportedMissileId = "LNC_waver_teleported";
private float minTeleportRange = 1500.0f,
jitterMinLevel = 20.0f,
fluxIncrease = 200.0f,
missileRange,
teleportRange,
targetRange,
jitterLevel;
//////////////////////
// DATA COLLECTING //
//////////////////////
public SCQ_LongbowMissileAI(MissileAPI missile, ShipAPI launchingShip) {
this.missile = missile;
this.ship = launchingShip;
this.weapon = missile.getWeapon();
missileRange = missile.getMaxFlightTime() * missile.getMaxSpeed();
missileRange = MathUtils.clamp(missileRange, 2500f, 3000f);
teleportRange = missile.getWeapon().getRange() - missileRange ;
teleportRange = MathUtils.clamp(teleportRange, 7000f, 10000f);
runOnce = false;
if (engine != Global.getCombatEngine()) {
engine = Global.getCombatEngine();
}
}
//////////////////////
// MAIN AI LOOP //
//////////////////////
@Override
public void advance(float amount) {
//skip the AI if the game is paused, the missile is engine-less or fading
if (engine == null) { // || engine.isPaused() || missile.isFading() || missile.isFizzling()
return;
}
if(missile != null && (missile.isFizzling() || missile.isFading() || missile.getFlightTime() > missile.getMaxFlightTime())){
// Vector2f loc, Vector2f vel, Color color, float size, float duration
engine.spawnExplosion(missile.getLocation(), missile.getVelocity(), new Color(112, 198, 240,200), 15f, 8f);
//public void applyDamage(CombatEntityAPI entity, Vector2f point, float damageAmount, DamageType damageType, float empAmount, boolean bypassShields, boolean dealsSoftFlux, Object source)
engine.applyDamage(missile, missile.getLocation(), missile.getHitpoints() * 2, DamageType.FRAGMENTATION, 0, true, false, missile.getSource());
engine.removeEntity(missile);
return;
}
//variables
if (targetLocation == null) {
if (ship.getMouseTarget() != null || !MathUtils.isWithinRange(missile.getLocation(), ship.getMouseTarget(), minTeleportRange)) {
targetLocation = ship.getMouseTarget();
} else if (ship.getShipTarget() != null && ship.getShipTarget().getLocation() != null) {
targetLocation = ship.getShipTarget().getLocation();
} else if (missile != null && AIUtils.getNearestEnemy(missile) != null) {
targetLocation = AIUtils.getNearestEnemy(missile).getLocation();
}
targetRange = Misc.getDistance(missile.getLocation(), targetLocation);
if (targetLocation != null) {
if (targetRange > teleportRange) {
float dir = Misc.getAngleInDegrees(missile.getLocation(), targetLocation);
targetLocation = Misc.getUnitVectorAtDegreeAngle(dir);
targetLocation.scale(teleportRange);
Vector2f.add(targetLocation, missile.getLocation(), targetLocation);
}
targetLocation = findClearLocation(missile, targetLocation);
}
}
if (!runOnce) {
if (ship.getCurrFlux() + fluxIncrease >= ship.getMaxFlux() || targetRange < minTeleportRange) {
Global.getSoundPlayer().playSound("short_range_lauch", 0.8f, 1.2f, ship.getLocation(), new Vector2f(0, 0));
runOnce = true;
return;
} else if (targetLocation != null) { // && (missileRange + teleportRange >= targetRange)
Global.getSoundPlayer().playSound("system_phase_skimmer", 0.8f, 1.2f, ship.getLocation(), new Vector2f(0,0));
ship.getFluxTracker().setCurrFlux(ship.getCurrFlux() + fluxIncrease);
teleportOnce(amount, missile, targetLocation);
jitterLevel = jitterMinLevel * 1 + (ship.getCurrFlux() / ship.getMaxFlux());
missile.setJitter(missile, JITTER_COLOR, jitterLevel, 4, 0f, 0 + (ship).getCurrFlux() / ship.getMaxFlux());
runOnce = true;
engine.removeEntity(missile);
return;
}
}
if (targetLocation == null) {
missile.giveCommand(ShipCommand.ACCELERATE);
} else {
float aimAngle = MathUtils.getShortestRotation(missile.getFacing(), VectorUtils.getAngle(missile.getLocation(), targetLocation));
if (Math.abs(aimAngle) < 45.0f) {
missile.giveCommand(ShipCommand.ACCELERATE);
}
if (aimAngle < 0f) {
missile.giveCommand(ShipCommand.TURN_RIGHT);
}
if (aimAngle > 0f) {
missile.giveCommand(ShipCommand.TURN_LEFT);
}
}
}
void teleportOnce(float amount, MissileAPI missile, Vector2f targetLocation){
if(targetLocation != null) {
Global.getSoundPlayer().playSound("system_phase_skimmer", 1.2f, 0.5f, missile.getLocation(), new Vector2f(0,0));
/**for (int i = 0; i < 12; i++) {
Vector2f cPoint = MathUtils.getRandomPointInCircle(targetLocation, 25f);
engine.addHitParticle(cPoint, new Vector2f ((float) Math.random() * 0.5f, (float) Math.random() * 0.5f), jitterLevel, jitterLevel, 0.5f, JITTER_COLOR);
}*/
if (ship != null && weapon != null && weapon.getShip() == ship) {
//engine.spawnProjectile(ShipAPI ship, WeaponAPI weapon, String weaponId, String projSpecId, Vector2f point, float angle, Vector2f shipVelocity)
engine.spawnProjectile(
null,
null,
missileTeleporterId,
teleportedMissileId,
targetLocation,
missile.getFacing(),
new Vector2f (0f, 0f) //new Vector2f(0,0)
);
} else return;
} else return;
}
private Vector2f findClearLocation(MissileAPI missile, Vector2f dest) {
if (isLocationClear(dest)) return dest;
float incr = 50f;
WeightedRandomPicker<Vector2f> tested = new WeightedRandomPicker<Vector2f>();
for (float distIndex = 1; distIndex <= 32f; distIndex *= 2f) {
float start = (float) Math.random() * 360f;
for (float angle = start; angle < start + 360; angle += 60f) {
Vector2f loc = Misc.getUnitVectorAtDegreeAngle(angle);
loc.scale(incr * distIndex);
Vector2f.add(dest, loc, loc);
tested.add(loc);
if (isLocationClear(loc)) {
return loc;
}
}
}
if (tested.isEmpty()) return dest; // shouldn't happen
return tested.pick();
}
private boolean isLocationClear(Vector2f loc) {
for (ShipAPI other : Global.getCombatEngine().getShips()) {
if (other.isShuttlePod()) continue;
if (other.isFighter()) continue;
float dist = Misc.getDistance(loc, other.getLocation());
float r = other.getCollisionRadius();
//r = Math.min(r, Misc.getTargetingRadius(loc, other, false) + r * 0.25f);
if (dist < r + minTeleportRange) {
return false;
}
}
for (CombatEntityAPI other : Global.getCombatEngine().getAsteroids()) {
float dist = Misc.getDistance(loc, other.getLocation());
if (dist < other.getCollisionRadius() + minTeleportRange) {
return false;
}
}
return true;
}
@Override
public CombatEntityAPI getTarget() {
return target;
}
@Override
public void setTarget(CombatEntityAPI target) {
this.target = target;
}
public void init(CombatEngineAPI engine) {}
}