Advertisement
LJLim

Tiandong flak fix (fighters/drones)

Dec 29th, 2016
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 14.88 KB | None | 0 0
  1. package data.scripts.plugins;
  2.  
  3. import com.fs.starfarer.api.Global;
  4. import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
  5. import com.fs.starfarer.api.combat.CollisionClass;
  6. import com.fs.starfarer.api.combat.CombatEngineAPI;
  7. import com.fs.starfarer.api.combat.CombatEntityAPI;
  8. import com.fs.starfarer.api.combat.DamageType;
  9. import com.fs.starfarer.api.combat.DamagingProjectileAPI;
  10. import com.fs.starfarer.api.combat.ShieldAPI;
  11. import com.fs.starfarer.api.combat.ShipAPI;
  12. import com.fs.starfarer.api.input.InputEventAPI;
  13. import data.scripts.util.tiandong_Twig;
  14. import java.awt.Color;
  15. import java.util.ArrayList;
  16. import java.util.HashSet;
  17. import java.util.Iterator;
  18. import java.util.LinkedList;
  19. import java.util.List;
  20. import java.util.Set;
  21. import org.dark.shaders.light.LightShader;
  22. import org.dark.shaders.light.StandardLight;
  23. import org.lazywizard.lazylib.CollisionUtils;
  24. import org.lazywizard.lazylib.MathUtils;
  25. import org.lazywizard.lazylib.VectorUtils;
  26. import org.lazywizard.lazylib.combat.CombatUtils;
  27. import org.lwjgl.util.vector.Vector2f;
  28.  
  29. public class tiandong_WeaponPlugin extends BaseEveryFrameCombatPlugin
  30. {
  31.     private static final float BURST_FLAK_AREA_DAMAGE = 80f;
  32.     private static final float BURST_FLAK_AREA_EFFECT = 75f;
  33.     private static final float BURST_FLAK_AREA_EFFECT_INNER = 50f;
  34.     private static final float BURST_FLAK_AREA_FORCE = 10f;
  35.     private static final Color BURST_FLAK_COLOR_CORE = new Color(255, 155, 155, 255);
  36.     private static final Color BURST_FLAK_COLOR_PARTICLE = new Color(255, 155, 155, 255);
  37.     private static final float BURST_FLAK_FLASH_DURATION = 0.2f;
  38.     private static final float BURST_FLAK_FUSE_RANGE = 50f;
  39.     private static final String BURST_FLAK_PROJECTILE_ID = "tiandong_burstflak_shot";
  40.     private static final String BURST_FLAK_SOUND_ID = "tiandong_burstflakcannon_explosion";
  41.     private static final String FLARE_PROJECTILE_ID = "tiandong_bulwarkCountermeasure";
  42.     private static final float VISUAL_RADIUS = 150f;
  43.     private static final float INNER_VISUAL_RADIUS = 50f;
  44.     private static final float LOOK_AHEAD_TIME = 0.067f;    // Extrapolate projectile position for this long in look-ahead for collisions
  45.     private static final Vector2f ZERO = new Vector2f();
  46.  
  47.     private final Set<DamagingProjectileAPI> DO_NOT_EXPLODE = new HashSet<>();
  48.  
  49.     public static void burstFlakExplode(DamagingProjectileAPI projectile, Vector2f point, CombatEngineAPI engine)
  50.     {
  51.         if (point == null)
  52.         {
  53.             return;
  54.         }
  55.  
  56.         tiandong_EffectsHook.createFlakShockwave(point);
  57.  
  58.         engine.addHitParticle(point, ZERO, INNER_VISUAL_RADIUS, 1f, BURST_FLAK_FLASH_DURATION, Color.WHITE);
  59.         engine.addHitParticle(point, ZERO, VISUAL_RADIUS, 0.4f, 0.6f, BURST_FLAK_COLOR_CORE);
  60.         Vector2f vel = new Vector2f();
  61.         for (int i = 0; i < 30; i++)
  62.         {
  63.             vel.set(((float) Math.random() * 1.25f + 0.25f) * VISUAL_RADIUS, 0f);
  64.             VectorUtils.rotate(vel, (float) Math.random() * 360f, vel);
  65.             engine.addSmoothParticle(projectile.getLocation(), vel, (float) Math.random() * 2.5f + 2.5f, 1f,
  66.                     (float) Math.random() * 0.3f + 0.6f, BURST_FLAK_COLOR_PARTICLE);
  67.         }
  68.  
  69.         StandardLight light = new StandardLight(projectile.getLocation(), ZERO, ZERO, null);
  70.         light.setColor(BURST_FLAK_COLOR_CORE);
  71.         light.setSize(VISUAL_RADIUS * 1.1f);
  72.         light.setIntensity(0.15f);
  73.         light.fadeOut(0.2f);
  74.         LightShader.addLight(light);
  75.  
  76.         Global.getSoundPlayer().playSound(BURST_FLAK_SOUND_ID, 1f, 1f, point, projectile.getVelocity());
  77.  
  78.         List<ShipAPI> ships = CombatUtils.getShipsWithinRange(point, BURST_FLAK_AREA_EFFECT);
  79.         List<CombatEntityAPI> targets = CombatUtils.getAsteroidsWithinRange(point, BURST_FLAK_AREA_EFFECT);
  80.         targets.addAll(CombatUtils.getMissilesWithinRange(point, BURST_FLAK_AREA_EFFECT));
  81.  
  82.         Iterator<ShipAPI> iter = ships.iterator();
  83.         while (iter.hasNext())
  84.         {
  85.             ShipAPI ship = iter.next();
  86.             if (ship.getCollisionClass() == CollisionClass.NONE)
  87.             {
  88.                 iter.remove();
  89.                 continue;
  90.             }
  91.  
  92.             if (!ship.isFighter() && !ship.isDrone())
  93.             {
  94.                 continue;
  95.             }
  96.  
  97.             boolean remove = false;
  98.             for (ShipAPI shp : ships)
  99.             {
  100.                 if (shp.getShield() != null && shp != ship)
  101.                 {
  102.                     if (shp.getShield().isWithinArc(ship.getLocation()) && shp.getShield().isOn()
  103.                             && MathUtils.getDistance(ship.getLocation(), shp.getShield().getLocation()) <= shp.getShield().getRadius())
  104.                     {
  105.                         remove = true;
  106.                     }
  107.                 }
  108.             }
  109.  
  110.             if (remove)
  111.             {
  112.                 iter.remove();
  113.             }
  114.         }
  115.  
  116.         ships = tiandong_Twig.getSortedAreaList(point, ships);
  117.         targets.addAll(ships);
  118.  
  119.         for (CombatEntityAPI tgt : targets)
  120.         {
  121.             /* No friendly fire for flak */
  122.             if (tgt.getOwner() == projectile.getOwner())
  123.             {
  124.                 continue;
  125.             }
  126.  
  127.             float distance = tiandong_Twig.getActualDistance(point, tgt, true);
  128.             float reduction = 1f;
  129.             if (distance > BURST_FLAK_AREA_EFFECT_INNER)
  130.             {
  131.                 reduction = (BURST_FLAK_AREA_EFFECT - distance) / (BURST_FLAK_AREA_EFFECT - BURST_FLAK_AREA_EFFECT_INNER);
  132.             }
  133.  
  134.             if (reduction <= 0f)
  135.             {
  136.                 continue;
  137.             }
  138.  
  139.             boolean shieldHit = false;
  140.             if (tgt instanceof ShipAPI)
  141.             {
  142.                 ShipAPI ship = (ShipAPI) tgt;
  143.                 if (ship.getShield() != null && ship.getShield().isWithinArc(point))
  144.                 {
  145.                     shieldHit = true;
  146.                 }
  147.             }
  148.  
  149.             Vector2f damagePoint;
  150.             if (shieldHit)
  151.             {
  152.                 ShipAPI ship = (ShipAPI) tgt;
  153.                 damagePoint = MathUtils.getPointOnCircumference(null, ship.getShield().getRadius(), VectorUtils.getAngle(ship.getShield().getLocation(), point));
  154.                 Vector2f.add(damagePoint, tgt.getLocation(), damagePoint);
  155.             }
  156.             else
  157.             {
  158.                 Vector2f projection = VectorUtils.getDirectionalVector(point, tgt.getLocation());
  159.                 projection.scale(tgt.getCollisionRadius());
  160.                 Vector2f.add(projection, tgt.getLocation(), projection);
  161.                 damagePoint = CollisionUtils.getCollisionPoint(point, projection, tgt);
  162.             }
  163.             if (damagePoint == null)
  164.             {
  165.                 damagePoint = point;
  166.             }
  167.             engine.applyDamage(tgt, damagePoint, BURST_FLAK_AREA_DAMAGE * reduction, DamageType.FRAGMENTATION, 0f, false, false, projectile.getSource());
  168.  
  169.             /* Force on projectiles is a little OP for a PD weapon */
  170.             if (!(tgt instanceof DamagingProjectileAPI))
  171.             {
  172.                 if (tgt instanceof ShipAPI)
  173.                 {
  174.                     CombatUtils.applyForce(tiandong_Twig.getRoot((ShipAPI) tgt), VectorUtils.getAngle(point, tgt.getLocation()), BURST_FLAK_AREA_FORCE * reduction);
  175.                 }
  176.                 else
  177.                 {
  178.                     CombatUtils.applyForce(tgt, VectorUtils.getAngle(point, tgt.getLocation()), BURST_FLAK_AREA_FORCE * reduction);
  179.                 }
  180.             }
  181.         }
  182.  
  183.         /* Don't want it exploding multiple times, do we? Also cleans up the look of it */
  184.         engine.removeEntity(projectile);
  185.     }
  186.     private CombatEngineAPI engine;
  187.  
  188.     @Override
  189.     public void advance(float amount, List<InputEventAPI> events)
  190.     {
  191.         if (engine == null)
  192.         {
  193.             return;
  194.         }
  195.         if (engine.isPaused())
  196.         {
  197.             return;
  198.         }
  199.  
  200.         List<DamagingProjectileAPI> projectiles = engine.getProjectiles();
  201.  
  202.         /* Clean up do-not-explode set of projectiles as needed */
  203.         List<DamagingProjectileAPI> toRemove = new ArrayList<>();
  204.         for (DamagingProjectileAPI proj : DO_NOT_EXPLODE)
  205.         {
  206.             if (!projectiles.contains(proj))    // No longer exists
  207.             {
  208.                 toRemove.add(proj);
  209.             }
  210.         }
  211.         DO_NOT_EXPLODE.removeAll(toRemove);
  212.  
  213.         int size = projectiles.size();
  214.         for (int i = 0; i < size; i++)
  215.         {
  216.             DamagingProjectileAPI proj = projectiles.get(i);
  217.             String spec = proj.getProjectileSpecId();
  218.             Vector2f loc = proj.getLocation();
  219.             if (spec == null)
  220.             {
  221.                 continue;
  222.             }
  223.  
  224.             switch (spec)
  225.             {
  226.                 case BURST_FLAK_PROJECTILE_ID:
  227.                 case FLARE_PROJECTILE_ID:
  228.                 {
  229.                     /* If the projectile already collided with something it's none of our business */
  230.                     if (proj.didDamage())
  231.                     {
  232.                         break;
  233.                     }
  234.                     if (DO_NOT_EXPLODE.contains(proj))
  235.                     {
  236.                         break;
  237.                     }
  238.  
  239.                     List<CombatEntityAPI> targets = new LinkedList<>();
  240.                     List<CombatEntityAPI> asteroids = CombatUtils.getAsteroidsWithinRange(loc, BURST_FLAK_FUSE_RANGE);
  241.                     targets.addAll(CombatUtils.getMissilesWithinRange(loc, BURST_FLAK_FUSE_RANGE));
  242.                     targets.addAll(CombatUtils.getShipsWithinRange(loc, BURST_FLAK_FUSE_RANGE));
  243.                     targets.addAll(asteroids);
  244.  
  245.                     for (CombatEntityAPI target : targets)
  246.                     {
  247.                         if (target.getCollisionClass() == CollisionClass.NONE)
  248.                         {
  249.                             continue;
  250.                         }
  251.                         if (target == proj.getSource()) // No collision checks with own (firing) ship
  252.                         {
  253.                             continue;
  254.                         }
  255.                        
  256.                         if (target.getOwner() == proj.getOwner())
  257.                         {
  258.                             // Don't check friendly projectiles for disarming / proximity fuse
  259.                             if (target instanceof DamagingProjectileAPI)
  260.                             {
  261.                                 continue;
  262.                             }
  263.  
  264.                             // ... or friendly fighters and drones
  265.                             else if (target instanceof ShipAPI)
  266.                             {
  267.                                 ShipAPI ship = (ShipAPI)target;
  268.                                 if ((ship.isFighter() || ship.isDrone()) && ship.isAlive())
  269.                                 {
  270.                                     continue;
  271.                                 }
  272.                             }
  273.                         }
  274.  
  275.                         /* Are we about to run into a shield? */
  276.                         if (target.getShield() != null)
  277.                         {
  278.                             Vector2f ahead = new Vector2f(loc).translate(proj.getVelocity().getX() * LOOK_AHEAD_TIME,
  279.                                     proj.getVelocity().getY() * LOOK_AHEAD_TIME);
  280.                             ShieldAPI shield = target.getShield();
  281.                             if (CollisionUtils.getCollides(loc, ahead, shield.getLocation(), shield.getRadius())
  282.                                     && shield.isWithinArc(ahead))   // Yes, we are
  283.                             {
  284.                                 if (target.getOwner() == proj.getOwner() || target.getOwner() > 1)  // Neutral or friendly shield, disarm
  285.                                 {
  286.                                     DO_NOT_EXPLODE.add(proj);
  287.                                 }
  288.                                 else    // Hostile shield, blow up
  289.                                 {
  290.                                     DO_NOT_EXPLODE.add(proj);
  291.                                     tiandong_WeaponPlugin.burstFlakExplode(proj, loc, engine);
  292.                                 }
  293.                                 break;
  294.                             }
  295.                         }
  296.  
  297.                         /* Handle any neutral or friendly things we're likely to run into if we've started fading out,
  298.                         this prevents double hits where we do direct hit damage *and* explode */
  299.                         if ((target.getOwner() == proj.getOwner() || target.getOwner() > 1))
  300.                         {
  301.                             float distance = tiandong_Twig.getActualDistance(loc, target, true);
  302.                             if ((distance <= BURST_FLAK_FUSE_RANGE))
  303.                             {
  304.                                 // Look-ahead hax
  305.                                 // If we'll impact a neutral or friendly target in 0.067 seconds, deactivate warhead
  306.                                 Vector2f ahead = new Vector2f(loc).translate(proj.getVelocity().getX() * LOOK_AHEAD_TIME,
  307.                                         proj.getVelocity().getY() * LOOK_AHEAD_TIME);
  308.                                 if (CollisionUtils.getCollisionPoint(loc, ahead, target) != null)
  309.                                 {
  310.                                     DO_NOT_EXPLODE.add(proj);
  311.                                     break;
  312.                                 }
  313.                             }
  314.                         }
  315.  
  316.                         /* Don't proximity fuse on asteroids, don't even bother checking them */
  317.                         if (asteroids.contains(target))
  318.                         {
  319.                             continue;
  320.                         }
  321.  
  322.                         /* Don't explode on neutrals or allies -- unless the projectile is neutral, in which case everything is fair game */
  323.                         if ((proj.getOwner() == 0) && (target.getOwner() != 1))
  324.                         {
  325.                             continue;
  326.                         }
  327.                         if ((proj.getOwner() == 1) && (target.getOwner() != 0))
  328.                         {
  329.                             continue;
  330.                         }
  331.  
  332.                         /* Check for targets in range */
  333.                         float distance = tiandong_Twig.getActualDistance(loc, target, true);
  334.                         if ((distance <= BURST_FLAK_FUSE_RANGE))
  335.                         {
  336.                             DO_NOT_EXPLODE.add(proj);
  337.                             tiandong_WeaponPlugin.burstFlakExplode(proj, loc, engine);
  338.                             break;
  339.                         }
  340.                     }
  341.  
  342.                     /* Detonate at the end-of-life, like real flak */
  343.                     if (proj.isFading() && !DO_NOT_EXPLODE.contains(proj))
  344.                     {
  345.                         DO_NOT_EXPLODE.add(proj);
  346.                         tiandong_WeaponPlugin.burstFlakExplode(proj, loc, engine);
  347.                         break;
  348.                     }
  349.  
  350.                     break;
  351.                 }
  352.                 default:
  353.             }
  354.         }
  355.     }
  356.  
  357.     @Override
  358.     public void init(CombatEngineAPI engine)
  359.     {
  360.         this.engine = engine;
  361.     }
  362. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement