Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package data.scripts.weapons;
- import com.fs.starfarer.api.Global;
- 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 java.util.*;
- import org.lazywizard.lazylib.CollectionUtils;
- import org.lazywizard.lazylib.MathUtils;
- import org.lazywizard.lazylib.VectorUtils;
- import org.lazywizard.lazylib.combat.AIUtils;
- import org.lazywizard.lazylib.combat.CombatUtils;
- import org.lwjgl.util.vector.Vector2f;
- //Based on LazyWizard's script
- public class SeekerAI implements MissileAIPlugin, GuidedMissileAI {
- // Our missile object
- private final MissileAPI missile;
- // Our current target (can be null)
- private CombatEntityAPI target;
- private final static float ACCELERATION = 1900f;
- private final static float MAX_SPEED = 430f;
- private final static float VELOCITY_DAMPING_FACTOR = 0.05f; // Lower numbers means it will snap in place more abruptly; set it to some negative number if you want it to corkscrew drunkenly
- public static ShipAPI findBestTarget(MissileAPI missile) {
- ShipAPI source = missile.getSource();
- if (source != null && source.getShipTarget() != null && !source.getShipTarget().isHulk()) {
- return source.getShipTarget();
- }
- return AIUtils.getNearestEnemy(missile);
- }
- public SeekerAI(MissileAPI missile, ShipAPI launchingShip) {
- this.missile = missile;
- // Support for 'fire at target by clicking on them' behavior
- List<ShipAPI> directTargets = CombatUtils.getShipsWithinRange(launchingShip.getMouseTarget(), 100f);
- if (!directTargets.isEmpty()) {
- Collections.sort(directTargets, new CollectionUtils.SortEntitiesByDistance(launchingShip.getMouseTarget()));
- for (ShipAPI tmp : directTargets) {
- if (!tmp.isHulk() && tmp.getOwner() != launchingShip.getOwner()) {
- setTarget(tmp);
- break;
- }
- }
- }
- // Otherwise, use default Sidewinder targeting AI
- if (target == null) {
- setTarget(findBestTarget(missile));
- }
- }
- @Override
- public void advance(float amount) {
- if (missile.isFizzling() || missile.isFading()) {
- return;
- }
- // If our current target is lost, assign a new one
- if (target == null // unset
- || (target instanceof ShipAPI && ((ShipAPI) target).isHulk()) // dead
- || (missile.getOwner() == target.getOwner()) // friendly
- || !Global.getCombatEngine().isEntityInPlay(target)) // completely removed
- {
- setTarget(findBestTarget(missile));
- missile.giveCommand(ShipCommand.ACCELERATE);
- return;
- }
- // Head towards the target, with target leading
- float distance = MathUtils.getDistance(target.getLocation(), missile.getLocation());
- Vector2f guidedTarget = intercept(missile.getLocation(), missile.getVelocity().length(), ACCELERATION, MAX_SPEED, target.getLocation(), target.getVelocity());
- if (guidedTarget == null) {
- // If the target is unreachable, try to lead anyway
- Vector2f projection = new Vector2f(target.getVelocity());
- float scalar = distance / missile.getVelocity().length();
- projection.scale(scalar);
- guidedTarget = Vector2f.add(target.getLocation(), projection, null);
- }
- float velocityFacing = VectorUtils.getFacing(missile.getVelocity());
- float absoluteDistance = MathUtils.getShortestRotation(velocityFacing, VectorUtils.getAngle(missile.getLocation(), guidedTarget));
- float angularDistance = MathUtils.getShortestRotation(missile.getFacing(), VectorUtils.getAngle(missile.getLocation(), guidedTarget));
- float compensationDifference = MathUtils.getShortestRotation(angularDistance, absoluteDistance);
- if (Math.abs(compensationDifference) <= 75f) {
- angularDistance += 0.5f * compensationDifference;
- }
- float absDVel = Math.abs(absoluteDistance);
- float absDAng = Math.abs(angularDistance);
- // Turn in the correct direction
- missile.giveCommand(angularDistance < 0 ? ShipCommand.TURN_RIGHT : ShipCommand.TURN_LEFT);
- // Always accelerate
- if (absDVel >= 45f || absDAng <= 45f) {
- missile.giveCommand(ShipCommand.ACCELERATE);
- }
- // Course correction
- if (absDAng < 5) {
- float MFlightAng = VectorUtils.getAngle(new Vector2f(0, 0), missile.getVelocity());
- float MFlightCC = MathUtils.getShortestRotation(missile.getFacing(), MFlightAng);
- if (Math.abs(MFlightCC) > 20) {
- missile.giveCommand(MFlightCC < 0 ? ShipCommand.STRAFE_LEFT : ShipCommand.STRAFE_RIGHT);
- }
- }
- //Damp angular velocity if we're getting close to the target angle
- if (absDAng < Math.abs(missile.getAngularVelocity()) * VELOCITY_DAMPING_FACTOR) {
- missile.setAngularVelocity(angularDistance / VELOCITY_DAMPING_FACTOR);
- }
- }
- public static Vector2f intercept(Vector2f point, float speed, float acceleration, float maxspeed, Vector2f target, Vector2f targetVel) {
- Vector2f difference = new Vector2f(target.x - point.x, target.y - point.y);
- float s = speed;
- float a = acceleration / 2f;
- float b = speed;
- float c = difference.length();
- Vector2f solutionSet = quad(a, b, c);
- if (solutionSet != null) {
- float t = Math.min(solutionSet.x, solutionSet.y);
- if (t < 0) {
- t = Math.max(solutionSet.x, solutionSet.y);
- }
- if (t > 0) {
- s = acceleration * t;
- s = s / 2f + speed;
- s = Math.min(s, maxspeed);
- }
- }
- a = targetVel.x * targetVel.x + targetVel.y * targetVel.y - s * s;
- b = 2 * (targetVel.x * difference.x + targetVel.y * difference.y);
- c = difference.x * difference.x + difference.y * difference.y;
- solutionSet = quad(a, b, c);
- Vector2f intercept = null;
- if (solutionSet != null) {
- float bestFit = Math.min(solutionSet.x, solutionSet.y);
- if (bestFit < 0) {
- bestFit = Math.max(solutionSet.x, solutionSet.y);
- }
- if (bestFit > 0) {
- intercept = new Vector2f(target.x + targetVel.x * bestFit, target.y + targetVel.y * bestFit);
- }
- }
- return intercept;
- }
- public static Vector2f quad(float a, float b, float c) {
- Vector2f solution = null;
- if (Float.compare(Math.abs(a), 0) == 0) {
- if (Float.compare(Math.abs(b), 0) == 0) {
- solution = (Float.compare(Math.abs(c), 0) == 0) ? new Vector2f(0, 0) : null;
- } else {
- solution = new Vector2f(-c / b, -c / b);
- }
- } else {
- float d = b * b - 4 * a * c;
- if (d >= 0) {
- d = (float) Math.sqrt(d);
- a = 2 * a;
- solution = new Vector2f((-b - d) / a, (-b + d) / a);
- }
- }
- return solution;
- }
- @Override
- public CombatEntityAPI getTarget() {
- return target;
- }
- @Override
- public void setTarget(CombatEntityAPI target) {
- this.target = target;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement