Advertisement
DarkRevenant

Untitled

Apr 19th, 2014
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 6.87 KB | None | 0 0
  1. package data.scripts.weapons;
  2.  
  3. import com.fs.starfarer.api.Global;
  4. import com.fs.starfarer.api.combat.CombatEntityAPI;
  5. import com.fs.starfarer.api.combat.DamageType;
  6. import com.fs.starfarer.api.combat.GuidedMissileAI;
  7. import com.fs.starfarer.api.combat.MissileAIPlugin;
  8. import com.fs.starfarer.api.combat.MissileAPI;
  9. import com.fs.starfarer.api.combat.ShipAPI;
  10. import com.fs.starfarer.api.combat.ShipCommand;
  11. import java.util.*;
  12. import org.lazywizard.lazylib.CollectionUtils;
  13. import org.lazywizard.lazylib.MathUtils;
  14. import org.lazywizard.lazylib.VectorUtils;
  15. import org.lazywizard.lazylib.combat.AIUtils;
  16. import org.lazywizard.lazylib.combat.CombatUtils;
  17. import org.lwjgl.util.vector.Vector2f;
  18.  
  19. //Based on LazyWizard's script
  20. public class SeekerAI implements MissileAIPlugin, GuidedMissileAI {
  21.  
  22.     // Our missile object
  23.     private final MissileAPI missile;
  24.     // Our current target (can be null)
  25.     private CombatEntityAPI target;
  26.  
  27.     private final static float VELOCITY_DAMPING_FACTOR = 0.2f; // Lower numbers means it will snap in place more abruptly; set it to some negative number if you want it to corkscrew drunkenly
  28.  
  29.     public static ShipAPI findBestTarget(MissileAPI missile) {
  30.         ShipAPI source = missile.getSource();
  31.         if (source != null && source.getShipTarget() != null
  32.                 && !source.getShipTarget().isHulk()) {
  33.             return source.getShipTarget();
  34.         }
  35.  
  36.         return AIUtils.getNearestEnemy(missile);
  37.     }
  38.  
  39.     public SeekerAI(MissileAPI missile, ShipAPI launchingShip) {
  40.         this.missile = missile;
  41.  
  42.         // Support for 'fire at target by clicking on them' behavior
  43.         List directTargets = CombatUtils.getShipsWithinRange(
  44.                 launchingShip.getMouseTarget(), 100f);
  45.         if (!directTargets.isEmpty()) {
  46.             Collections.sort(directTargets, new CollectionUtils.SortEntitiesByDistance(launchingShip.getMouseTarget()));
  47.             for (Iterator<ShipAPI> iter = directTargets.iterator(); iter.hasNext();) {
  48.                 ShipAPI tmp = iter.next();
  49.                 if (!tmp.isHulk() && tmp.getOwner() != launchingShip.getOwner()) {
  50.                     setTarget(tmp);
  51.                     break;
  52.                 }
  53.             }
  54.         }
  55.  
  56.         // Otherwise, use default Sidewinder targeting AI
  57.         if (target == null) {
  58.             setTarget(findBestTarget(missile));
  59.         }
  60.     }
  61.  
  62.     @Override
  63.     public void advance(float amount) {
  64.         // Apparently commands still work while fizzling
  65.         if (missile.isFading() || missile.isFizzling()) {
  66.             Global.getCombatEngine().applyDamage(missile, missile.getLocation(), missile.getHitpoints() * 2f, DamageType.FRAGMENTATION, 0f, false, false, missile);
  67.             return;
  68.         }
  69.  
  70.         // If our current target is lost, assign a new one
  71.         if (target == null // unset
  72.                 || (target instanceof ShipAPI && ((ShipAPI) target).isHulk()) // dead
  73.                 || (missile.getOwner() == target.getOwner()) // friendly
  74.                 || !Global.getCombatEngine().isEntityInPlay(target)) // completely removed
  75.         {
  76.             setTarget(findBestTarget(missile));
  77.             missile.giveCommand(ShipCommand.ACCELERATE);
  78.             return;
  79.         }
  80.  
  81.         // Head towards the target, with target leading
  82.         Vector2f guidedTarget = intercept(missile.getLocation(), missile.getVelocity().length(), target.getLocation(), target.getVelocity());
  83.         if (guidedTarget == null) {
  84.             // If the target is unreachable, try to lead anyway
  85.             Vector2f projection = new Vector2f(target.getVelocity());
  86.             float scalar = MathUtils.getDistance(target.getLocation(), missile.getLocation()) / missile.getVelocity().length();
  87.             projection.x *= scalar;
  88.             projection.y *= scalar;
  89.             guidedTarget = Vector2f.add(target.getLocation(), projection, null);
  90.         }
  91.  
  92.         float angularDistance = MathUtils.getShortestRotation(missile.getFacing(), VectorUtils.getAngle(missile.getLocation(), guidedTarget));
  93.         float absAngD = Math.abs(angularDistance);
  94.  
  95.         // Turn in the correct direction
  96.         missile.giveCommand(angularDistance < 0 ? ShipCommand.TURN_RIGHT : ShipCommand.TURN_LEFT);
  97.  
  98.         // Always accelerate
  99.         missile.giveCommand(ShipCommand.ACCELERATE);
  100.  
  101.         // Course correction
  102.         if (absAngD < 5) {
  103.             float MFlightAng = VectorUtils.getAngle(new Vector2f(0, 0), missile.getVelocity());
  104.             float MFlightCC = MathUtils.getShortestRotation(missile.getFacing(), MFlightAng);
  105.             if (Math.abs(MFlightCC) > 20) {
  106.                 missile.giveCommand(MFlightCC < 0 ? ShipCommand.STRAFE_LEFT : ShipCommand.STRAFE_RIGHT);
  107.             }
  108.         }
  109.  
  110.         //Damp angular velocity if we're getting close to the target angle
  111.         if (Math.abs(angularDistance) < Math.abs(missile.getAngularVelocity()) * VELOCITY_DAMPING_FACTOR) {
  112.             missile.setAngularVelocity(angularDistance / VELOCITY_DAMPING_FACTOR);
  113.         }
  114.     }
  115.  
  116.     // Will be in the next LazyLib, courtesy of DarkRevenant
  117.     public static Vector2f intercept(Vector2f point, float speed, Vector2f target, Vector2f targetVel) {
  118.         Vector2f difference = new Vector2f(target.x - point.x, target.y - point.y);
  119.  
  120.         float a = targetVel.x * targetVel.x + targetVel.y * targetVel.y - speed * speed;
  121.         float b = 2 * (targetVel.x * difference.x + targetVel.y * difference.y);
  122.         float c = difference.x * difference.x + difference.y * difference.y;
  123.  
  124.         Vector2f solutionSet = quad(a, b, c);
  125.  
  126.         Vector2f intercept = null;
  127.         if (solutionSet != null) {
  128.             float bestFit = Math.min(solutionSet.x, solutionSet.y);
  129.             if (bestFit < 0) {
  130.                 bestFit = Math.max(solutionSet.x, solutionSet.y);
  131.             }
  132.             if (bestFit > 0) {
  133.                 intercept = new Vector2f(target.x + targetVel.x * bestFit, target.y + targetVel.y * bestFit);
  134.             }
  135.         }
  136.  
  137.         return intercept;
  138.     }
  139.  
  140.     public static Vector2f quad(float a, float b, float c) {
  141.         Vector2f solution = null;
  142.         if (Float.compare(Math.abs(a), 0) == 0) {
  143.             if (Float.compare(Math.abs(b), 0) == 0) {
  144.                 solution = (Float.compare(Math.abs(c), 0) == 0) ? new Vector2f(0, 0) : null;
  145.             } else {
  146.                 solution = new Vector2f(-c / b, -c / b);
  147.             }
  148.         } else {
  149.             float d = b * b - 4 * a * c;
  150.             if (d >= 0) {
  151.                 d = (float) Math.sqrt(d);
  152.                 a = 2 * a;
  153.                 solution = new Vector2f((-b - d) / a, (-b + d) / a);
  154.             }
  155.         }
  156.         return solution;
  157.     }
  158.  
  159.     @Override
  160.     public CombatEntityAPI getTarget() {
  161.         return target;
  162.     }
  163.  
  164.     @Override
  165.     public void setTarget(CombatEntityAPI target) {
  166.         this.target = target;
  167.     }
  168. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement