Advertisement
DarkRevenant

Untitled

Apr 16th, 2014
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 15.37 KB | None | 0 0
  1. package data.scripts.plugins;
  2.  
  3. import com.fs.starfarer.api.Global;
  4. import com.fs.starfarer.api.combat.CombatEngineAPI;
  5. import com.fs.starfarer.api.combat.CombatEntityAPI;
  6. import com.fs.starfarer.api.combat.DamageType;
  7. import com.fs.starfarer.api.combat.DamagingProjectileAPI;
  8. import com.fs.starfarer.api.combat.EveryFrameCombatPlugin;
  9. import com.fs.starfarer.api.combat.MutableShipStatsAPI;
  10. import com.fs.starfarer.api.combat.ShipAPI;
  11. import com.fs.starfarer.api.combat.ShipSystemAPI;
  12. import com.fs.starfarer.api.plugins.ShipSystemStatsScript;
  13. import com.fs.starfarer.api.util.IntervalUtil;
  14. import java.awt.Color;
  15. import java.util.*;
  16. import org.lazywizard.lazylib.MathUtils;
  17. import org.lazywizard.lazylib.VectorUtils;
  18. import org.lazywizard.lazylib.combat.CombatUtils;
  19. import org.lwjgl.util.vector.Vector2f;
  20.  
  21. public class exigency_Repulsor implements ShipSystemStatsScript, EveryFrameCombatPlugin {
  22.  
  23.     public final IntervalUtil clock = new IntervalUtil(0.1f, 0.3f); // 0.2 seconds on average
  24.     public static final float REPULSOR_ACTIVE_TIME = 10.0f + 1.0f; // 10 seconds + 1 sec cooldown
  25.     public static final float REPULSOR_STAGE_1_END = 0.1f; // grow from      0 sec to 1 sec
  26.     public static final float REPULSOR_STAGE_2_END = 0.9f; // maintain from  1 sec to 9 sec
  27.     public static final float REPULSOR_STAGE_3_END = 1.0f; // shrink from    9 sec to 10 sec
  28.     public static final int REPULSOR_MAXIMUM_PARTICLES_PER_FRAME = 30; //limits the amount spawned on everyframe
  29.     public static final float REPULSOR_PARTICLES_PER_EXECUTION_AS_REPULSOR_RADIUS_FACTOR = 0.04f;
  30.     public static final float REPULSOR_PARTICLE_DISTRIBUTION_BIAS = 0.9f;
  31.     public static final float REPULSOR_ORBIT_DIR = 1.0f; // or -1.0f
  32.     public static final float MIN_REPULSOR_RADIUS = 50f;
  33.     public static final float COLLISION_RADIUS_REPULSOR_RADIUS_FACTOR = 1.25f;
  34.     public static final float REPULSOR_SIZE_FACTOR_MIN = 0.02f;
  35.     public static final float REPULSOR_SIZE_FACTOR_MAX = 0.10f;
  36.     public static final float MIN_REPULSOR_PARTICLE_SIZE = 5f;
  37.     public static final float MIN_REPULSOR_PARTICLE_DURATION = 0.2f;
  38.     public static final float MAX_REPULSOR_PARTICLE_DURATION = 1.25f;
  39.     public static final float REPULSOR_SPEED_FACTOR = 0.6f;
  40.     public static final float REPULSOR_VELOCITY_ANGLE_MOD = 10.0f;
  41.     public static final float REPULSOR_VELOCITY_ANGLE_CONSTANT = 90.0f + REPULSOR_VELOCITY_ANGLE_MOD;
  42.     public static final float MIN_REPULSOR_COLOR_YELLOW = 32f;
  43.     public static final float MAX_REPULSOR_COLOR_YELLOW = 160f;
  44.     public static final float MIN_REPULSOR_ALPHA = 64f;
  45.     public static final float MAX_REPULSOR_ALPHA = 128f;
  46.     public static final float FEEDBACK_PARTICLE_SIZEFACTOR = 4f;
  47.     public static final float FEEDBACK_PARTICLE_BRIGHTNESS = 1f;
  48.     public static final float FEEDBACK_PARTICLE_DURATION = 1f;
  49.     public static final int FEEDBACK_PARTICLE_MAX_PER_REPULSE = 12;
  50.     public static final String FEEDBACK_SOUND_ID = "exigency_repulse";
  51.     public CombatEngineAPI activeEngine; // assigned per combat
  52.     public static final Map<CombatEntityAPI, Float> reflecting = new HashMap(); // map of ships with active systems
  53.  
  54.     @Override
  55.     public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
  56.         if (stats.getEntity() != null && !reflecting.containsKey(stats.getEntity())) {
  57.             reflecting.put(stats.getEntity(), Float.valueOf(Global.getCombatEngine().getTotalElapsedTime(false)));
  58.         }
  59.     }
  60.  
  61.     @Override
  62.     public void unapply(MutableShipStatsAPI stats, String id) {
  63.         reflecting.remove(stats.getEntity());
  64.     }
  65.  
  66.     @Override
  67.     public StatusData getStatusData(int index, State state, float effectLevel) {
  68.         if (index == 0) {
  69.             return new StatusData("repelling nearby enemy objects", false);
  70.         }
  71.         return null;
  72.     }
  73.  
  74.     @Override
  75.     public void init(CombatEngineAPI engine) {
  76.     }
  77.  
  78.     @Override
  79.     public void advance(float amount, List events) {
  80.         // Temp fix for .6.2a bugs
  81.         if (activeEngine != Global.getCombatEngine()) {
  82.             reflecting.clear();
  83.             this.activeEngine = Global.getCombatEngine();
  84.             return;
  85.         }
  86.         //activeEngine.addFloatingText(activeEngine.getPlayerShip().getLocation(), "RUNNING REPULSOR", 200f, Color.BLUE, activeEngine.getPlayerShip(), 1f, 0f);
  87.         if (activeEngine.isPaused()) {
  88.             return;
  89.         }
  90.  
  91.         // throttle execution to a minimum interval
  92.         clock.advance(amount);
  93.         if (!clock.intervalElapsed()) {
  94.             return;
  95.         }
  96.         float elapsed = Global.getCombatEngine().getTotalElapsedTime(false);
  97.  
  98.         // push ships/asteroids away from this ship
  99.         // reprogram/reflect missiles/projectiles back to their source
  100.         for (Iterator<Map.Entry<CombatEntityAPI, Float>> iter = reflecting.entrySet().iterator(); iter.hasNext();) {
  101.             Map.Entry<CombatEntityAPI, Float> tmp = iter.next();
  102.             CombatEntityAPI entity = tmp.getKey();
  103.             if (entity instanceof ShipAPI) {
  104.                 ShipAPI ship = (ShipAPI) entity;
  105.  
  106.                 if (ship.isHulk() || !activeEngine.getShips().contains(ship)) {
  107.                     iter.remove();
  108.                     continue;
  109.                 }
  110.  
  111.                 // the percentage of the repulsor animation that has executed for this ship based on when it was activated
  112.                 float activated_timestamp = (Float) tmp.getValue();
  113.                 float anim_pct_overall = (elapsed - activated_timestamp) / REPULSOR_ACTIVE_TIME;
  114.                 if (anim_pct_overall >= 1.0f) {
  115.                     // Don't execute anything if it's done
  116.                     // But don't remove it from the list either because that happens during unapply anyway
  117.                     continue;
  118.                 }
  119.  
  120.                 int anim_stage;
  121.                 if (anim_pct_overall >= REPULSOR_STAGE_2_END) {
  122.                     anim_stage = 2;
  123.                 } else if (anim_pct_overall >= REPULSOR_STAGE_1_END) {
  124.                     anim_stage = 1;
  125.                 } else {
  126.                     anim_stage = 0;
  127.                 }
  128.  
  129.                 //The ship's location, used for the rest of the code.
  130.                 Vector2f shipLoc = ship.getLocation();
  131.                 Vector2f shipVec = ship.getVelocity();
  132.  
  133.                 //Gets list of nearby ships and projectiles and pushes them out of the radius
  134.                 float factor = 1.0f;
  135.                 if (anim_stage == 0) {
  136.                     factor = anim_pct_overall / REPULSOR_STAGE_1_END;
  137.                 } else if (anim_stage == 2) {
  138.                     factor = 1.0f - ((anim_pct_overall - REPULSOR_STAGE_2_END) / (REPULSOR_STAGE_3_END - REPULSOR_STAGE_2_END));
  139.                 }
  140.                 // if anim stage is 1, radius should be maintained, thus 1.0f (default) should be used
  141.                 float animation_stage_based_radius_factor = factor * COLLISION_RADIUS_REPULSOR_RADIUS_FACTOR;
  142.                 float repulseRadius = Math.max(ship.getCollisionRadius() * animation_stage_based_radius_factor, MIN_REPULSOR_RADIUS);
  143.  
  144.                 //Global.getLogger(this.getClass()).debug( "anim_pct_overall="+anim_pct_overall+"  repulseRadius="+repulseRadius+"  factor="+factor+"  anim_stage="+anim_stage );
  145.                 //Blue radiation from our repulsor pulses out with each use pulse
  146.                 int particle_count = (int) (repulseRadius * REPULSOR_PARTICLES_PER_EXECUTION_AS_REPULSOR_RADIUS_FACTOR);
  147.  
  148.                 //Added a limit to how many particles appear in the screen per repulsor each frame
  149.                 if (particle_count > REPULSOR_MAXIMUM_PARTICLES_PER_FRAME) {
  150.                     particle_count = REPULSOR_MAXIMUM_PARTICLES_PER_FRAME;
  151.                 }
  152.  
  153.                 for (int i = 0; i < particle_count; i++) {
  154.                     float dist = repulseRadius * (float) getBiasedRandom(REPULSOR_PARTICLE_DISTRIBUTION_BIAS, 0, 1);
  155.                     float angle = (float) Math.random() * 360f;
  156.                     Vector2f randPoint = MathUtils.getPointOnCircumference(shipLoc, dist, angle);
  157.                     float randSize = MathUtils.getRandomNumberInRange(REPULSOR_SIZE_FACTOR_MIN * repulseRadius, REPULSOR_SIZE_FACTOR_MAX * repulseRadius);
  158.                     if (randSize < MIN_REPULSOR_PARTICLE_SIZE) {
  159.                         randSize = MIN_REPULSOR_PARTICLE_SIZE;
  160.                     }
  161.                     Vector2f velocity = MathUtils.getPointOnCircumference(shipVec, (REPULSOR_SPEED_FACTOR * dist), angle + REPULSOR_ORBIT_DIR * REPULSOR_VELOCITY_ANGLE_CONSTANT);
  162.                     float randDur = 0.1f + MathUtils.getRandomNumberInRange(MIN_REPULSOR_PARTICLE_DURATION, MAX_REPULSOR_PARTICLE_DURATION);
  163.                     int yelVal = (int) (MIN_REPULSOR_COLOR_YELLOW + Math.random() * (MAX_REPULSOR_COLOR_YELLOW - MIN_REPULSOR_COLOR_YELLOW));
  164.                     Color color = new Color(0, yelVal, 255, 255);
  165.                     ///
  166.                     //activeEngine.addSmoothParticle( randPoint, velocity, randSize, 1f, randDur, color );
  167.                     activeEngine.addHitParticle(randPoint, velocity, randSize, 1f, randDur, color);
  168.                 }
  169.  
  170.                 List<ShipAPI> nearbyEnemies = CombatUtils.getShipsWithinRange(shipLoc, repulseRadius);//List of enemies to push back, smoothly
  171.                 for (ShipAPI thisEnemy : nearbyEnemies) {
  172.                     //Don't push phased ships.
  173.                     ShipSystemAPI cloak = thisEnemy.getPhaseCloak();
  174.                     if (cloak != null && cloak.isActive()) {
  175.                         continue; // phase ship, skip it
  176.                     }
  177.                     push(ship, thisEnemy); // push it
  178.                     //Test code here
  179.                     //activeEngine.addFloatingText(thisEnemyLoc, "Repulsed with " + pushVec.x + pushVec.y + " force!", 20f, Color.BLUE, ship, 1f, 0f);
  180.                 }
  181.  
  182.                 List<CombatEntityAPI> nearbyAsteroids = CombatUtils.getAsteroidsWithinRange(shipLoc, repulseRadius); //List of enemies to push back, smoothly
  183.                 for (CombatEntityAPI asteroid : nearbyAsteroids) {
  184.                     push(ship, asteroid); // push it always
  185.                 }
  186.  
  187.                 //Iterates through nearby enemy projectiles and reverses their course, "repulsing" them.
  188.                 //In theory, two groups with Repulsors active could ping-pong shots back and forth at one another nearly forever...
  189.                 //In reality, the time intervals don't allow for it.
  190.                 int numRepulseParticles = 0;
  191.                 for (DamagingProjectileAPI thisProj : activeEngine.getProjectiles()) {
  192.                     if (thisProj.getOwner() != ship.getOwner() && Math.random() > 0.2f)//If not ours and if luck favors us, then...
  193.                     {
  194.                         //Get the projectile to be reversed's vital stats, including the inverse of its velocity (to send it right back where it came from)
  195.                         Vector2f thisProjLoc = thisProj.getLocation();
  196.                         Vector2f thisProjVel = thisProj.getVelocity();
  197.                         if (MathUtils.getDistanceSquared(shipLoc, thisProjLoc) > (repulseRadius * repulseRadius)) {
  198.                             continue;
  199.                         }
  200.  
  201.                         if (numRepulseParticles < FEEDBACK_PARTICLE_MAX_PER_REPULSE) {
  202.                             numRepulseParticles++;
  203.                             // Creates a handy feedback effect
  204.                             int yelVal = (int) (MIN_REPULSOR_COLOR_YELLOW + Math.random() * (MAX_REPULSOR_COLOR_YELLOW - MIN_REPULSOR_COLOR_YELLOW));
  205.                             Color color = new Color(0, yelVal, 255, 255);
  206.                             float scaleFactor;
  207.                             if (thisProj.getDamageType() == DamageType.FRAGMENTATION) {
  208.                                 scaleFactor = (float) Math.sqrt(thisProj.getDamageAmount() * 0.25f);
  209.                             } else {
  210.                                 scaleFactor = (float) Math.sqrt(thisProj.getDamageAmount() * 1f);
  211.                             }
  212.  
  213.                             scaleFactor = Math.min(scaleFactor, 40);
  214.  
  215.                             activeEngine.addHitParticle(thisProjLoc, ship.getVelocity(),
  216.                                     FEEDBACK_PARTICLE_SIZEFACTOR * scaleFactor,
  217.                                     FEEDBACK_PARTICLE_BRIGHTNESS,
  218.                                     FEEDBACK_PARTICLE_DURATION,
  219.                                     color);
  220.                             if (Math.random() < 0.2f + thisProj.getCollisionRadius() / 10f) {
  221.                                 Global.getSoundPlayer().playSound(FEEDBACK_SOUND_ID, (float) Math.random() * 0.2f + 0.9f, 0.7f + scaleFactor / 30f, thisProjLoc, new Vector2f());
  222.                             }
  223.                         }
  224.  
  225.                         // Reverse projectile with a 10 degree margin of error
  226.                         float returnAngle = MathUtils.clampAngle(VectorUtils.getFacing(thisProjVel) + MathUtils.getRandomNumberInRange(170f, 190f));
  227.                         thisProjVel.set(MathUtils.getPointOnCircumference(null, thisProjVel.length() * 1.3f, returnAngle));
  228.  
  229.                         thisProj.setFacing(returnAngle);
  230.                         thisProj.setOwner(ship.getOwner());
  231.                         thisProj.setSource(ship);
  232.                     }
  233.  
  234.                     //activeEngine.addFloatingText(thisProjLoc, "Repulsed with " + pushVec.x + pushVec.y + " force!", 20f, Color.BLUE, ship, 1f, 0f);
  235.                 }
  236.             } else {
  237.                 // If null or not a ship, it gets removed.
  238.                 iter.remove();
  239.             }
  240.         }
  241.     }
  242.     Random tRandom = new Random();
  243.  
  244.     private double getBiasedRandom(double bias, double min, double max) {
  245.         double centered_depth_perc = 0.3;
  246.         double centered_depth_abs = (max - min) * centered_depth_perc;
  247.         double center = 0.5;
  248.         double rndBiased;
  249.  
  250.         double rndCentered = center + tRandom.nextGaussian() * centered_depth_abs; // generate centered random number.
  251.  
  252.         if (rndCentered >= center) {
  253.             rndBiased = (rndCentered - center) * (max - bias) + bias;
  254.         } else {
  255.             rndBiased = bias - (center - rndCentered) * (bias - min);
  256.         }
  257.  
  258.         // the following two tests will be as more important as centered_depth_perc
  259.         // get bigger.
  260.         if (rndBiased > max) {
  261.             rndBiased = max;
  262.         }
  263.  
  264.         if (rndBiased < min) {
  265.             rndBiased = min;
  266.         }
  267.  
  268.         return rndBiased;
  269.     }
  270.  
  271.     private void push(CombatEntityAPI source, CombatEntityAPI target) {
  272.         if (source.getOwner() == target.getOwner()) {
  273.             return;
  274.         }
  275.         Vector2f source_loc = source.getLocation();
  276.         Vector2f target_loc = target.getLocation();
  277.         Vector2f pushVec = new Vector2f(target_loc.x - source_loc.x, target_loc.y - source_loc.y);//Get the vector going from A to B
  278.         float magnitude = (1f / pushVec.lengthSquared()); //Get the magnitude of the vector (usually very small)
  279.         float mass = Math.max(1f, target.getMass());
  280.         magnitude /= mass;
  281.         pushVec.x *= magnitude * 1000000f;
  282.         pushVec.y *= magnitude * 1000000f;
  283.         Vector2f enemyVel = target.getVelocity(); //Get the velocity of the ship, and add the new vector to it.
  284.         enemyVel.x += pushVec.x;
  285.         enemyVel.y += pushVec.y;
  286.     }
  287. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement