Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package data.scripts.plugins;
- import com.fs.starfarer.api.Global;
- import com.fs.starfarer.api.combat.CombatEngineAPI;
- import com.fs.starfarer.api.combat.CombatEntityAPI;
- import com.fs.starfarer.api.combat.DamageType;
- import com.fs.starfarer.api.combat.DamagingProjectileAPI;
- import com.fs.starfarer.api.combat.EveryFrameCombatPlugin;
- import com.fs.starfarer.api.combat.MutableShipStatsAPI;
- import com.fs.starfarer.api.combat.ShipAPI;
- import com.fs.starfarer.api.combat.ShipSystemAPI;
- import com.fs.starfarer.api.plugins.ShipSystemStatsScript;
- import com.fs.starfarer.api.util.IntervalUtil;
- import java.awt.Color;
- import java.util.*;
- import org.lazywizard.lazylib.MathUtils;
- import org.lazywizard.lazylib.VectorUtils;
- import org.lazywizard.lazylib.combat.CombatUtils;
- import org.lwjgl.util.vector.Vector2f;
- public class exigency_Repulsor implements ShipSystemStatsScript, EveryFrameCombatPlugin {
- public final IntervalUtil clock = new IntervalUtil(0.1f, 0.3f); // 0.2 seconds on average
- public static final float REPULSOR_ACTIVE_TIME = 10.0f + 1.0f; // 10 seconds + 1 sec cooldown
- public static final float REPULSOR_STAGE_1_END = 0.1f; // grow from 0 sec to 1 sec
- public static final float REPULSOR_STAGE_2_END = 0.9f; // maintain from 1 sec to 9 sec
- public static final float REPULSOR_STAGE_3_END = 1.0f; // shrink from 9 sec to 10 sec
- public static final int REPULSOR_MAXIMUM_PARTICLES_PER_FRAME = 30; //limits the amount spawned on everyframe
- public static final float REPULSOR_PARTICLES_PER_EXECUTION_AS_REPULSOR_RADIUS_FACTOR = 0.04f;
- public static final float REPULSOR_PARTICLE_DISTRIBUTION_BIAS = 0.9f;
- public static final float REPULSOR_ORBIT_DIR = 1.0f; // or -1.0f
- public static final float MIN_REPULSOR_RADIUS = 50f;
- public static final float COLLISION_RADIUS_REPULSOR_RADIUS_FACTOR = 1.25f;
- public static final float REPULSOR_SIZE_FACTOR_MIN = 0.02f;
- public static final float REPULSOR_SIZE_FACTOR_MAX = 0.10f;
- public static final float MIN_REPULSOR_PARTICLE_SIZE = 5f;
- public static final float MIN_REPULSOR_PARTICLE_DURATION = 0.2f;
- public static final float MAX_REPULSOR_PARTICLE_DURATION = 1.25f;
- public static final float REPULSOR_SPEED_FACTOR = 0.6f;
- public static final float REPULSOR_VELOCITY_ANGLE_MOD = 10.0f;
- public static final float REPULSOR_VELOCITY_ANGLE_CONSTANT = 90.0f + REPULSOR_VELOCITY_ANGLE_MOD;
- public static final float MIN_REPULSOR_COLOR_YELLOW = 32f;
- public static final float MAX_REPULSOR_COLOR_YELLOW = 160f;
- public static final float MIN_REPULSOR_ALPHA = 64f;
- public static final float MAX_REPULSOR_ALPHA = 128f;
- public static final float FEEDBACK_PARTICLE_SIZEFACTOR = 4f;
- public static final float FEEDBACK_PARTICLE_BRIGHTNESS = 1f;
- public static final float FEEDBACK_PARTICLE_DURATION = 1f;
- public static final int FEEDBACK_PARTICLE_MAX_PER_REPULSE = 12;
- public static final String FEEDBACK_SOUND_ID = "exigency_repulse";
- public CombatEngineAPI activeEngine; // assigned per combat
- public static final Map<CombatEntityAPI, Float> reflecting = new HashMap(); // map of ships with active systems
- @Override
- public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
- if (stats.getEntity() != null && !reflecting.containsKey(stats.getEntity())) {
- reflecting.put(stats.getEntity(), Float.valueOf(Global.getCombatEngine().getTotalElapsedTime(false)));
- }
- }
- @Override
- public void unapply(MutableShipStatsAPI stats, String id) {
- reflecting.remove(stats.getEntity());
- }
- @Override
- public StatusData getStatusData(int index, State state, float effectLevel) {
- if (index == 0) {
- return new StatusData("repelling nearby enemy objects", false);
- }
- return null;
- }
- @Override
- public void init(CombatEngineAPI engine) {
- }
- @Override
- public void advance(float amount, List events) {
- // Temp fix for .6.2a bugs
- if (activeEngine != Global.getCombatEngine()) {
- reflecting.clear();
- this.activeEngine = Global.getCombatEngine();
- return;
- }
- //activeEngine.addFloatingText(activeEngine.getPlayerShip().getLocation(), "RUNNING REPULSOR", 200f, Color.BLUE, activeEngine.getPlayerShip(), 1f, 0f);
- if (activeEngine.isPaused()) {
- return;
- }
- // throttle execution to a minimum interval
- clock.advance(amount);
- if (!clock.intervalElapsed()) {
- return;
- }
- float elapsed = Global.getCombatEngine().getTotalElapsedTime(false);
- // push ships/asteroids away from this ship
- // reprogram/reflect missiles/projectiles back to their source
- for (Iterator<Map.Entry<CombatEntityAPI, Float>> iter = reflecting.entrySet().iterator(); iter.hasNext();) {
- Map.Entry<CombatEntityAPI, Float> tmp = iter.next();
- CombatEntityAPI entity = tmp.getKey();
- if (entity instanceof ShipAPI) {
- ShipAPI ship = (ShipAPI) entity;
- if (ship.isHulk() || !activeEngine.getShips().contains(ship)) {
- iter.remove();
- continue;
- }
- // the percentage of the repulsor animation that has executed for this ship based on when it was activated
- float activated_timestamp = (Float) tmp.getValue();
- float anim_pct_overall = (elapsed - activated_timestamp) / REPULSOR_ACTIVE_TIME;
- if (anim_pct_overall >= 1.0f) {
- // Don't execute anything if it's done
- // But don't remove it from the list either because that happens during unapply anyway
- continue;
- }
- int anim_stage;
- if (anim_pct_overall >= REPULSOR_STAGE_2_END) {
- anim_stage = 2;
- } else if (anim_pct_overall >= REPULSOR_STAGE_1_END) {
- anim_stage = 1;
- } else {
- anim_stage = 0;
- }
- //The ship's location, used for the rest of the code.
- Vector2f shipLoc = ship.getLocation();
- Vector2f shipVec = ship.getVelocity();
- //Gets list of nearby ships and projectiles and pushes them out of the radius
- float factor = 1.0f;
- if (anim_stage == 0) {
- factor = anim_pct_overall / REPULSOR_STAGE_1_END;
- } else if (anim_stage == 2) {
- factor = 1.0f - ((anim_pct_overall - REPULSOR_STAGE_2_END) / (REPULSOR_STAGE_3_END - REPULSOR_STAGE_2_END));
- }
- // if anim stage is 1, radius should be maintained, thus 1.0f (default) should be used
- float animation_stage_based_radius_factor = factor * COLLISION_RADIUS_REPULSOR_RADIUS_FACTOR;
- float repulseRadius = Math.max(ship.getCollisionRadius() * animation_stage_based_radius_factor, MIN_REPULSOR_RADIUS);
- //Global.getLogger(this.getClass()).debug( "anim_pct_overall="+anim_pct_overall+" repulseRadius="+repulseRadius+" factor="+factor+" anim_stage="+anim_stage );
- //Blue radiation from our repulsor pulses out with each use pulse
- int particle_count = (int) (repulseRadius * REPULSOR_PARTICLES_PER_EXECUTION_AS_REPULSOR_RADIUS_FACTOR);
- //Added a limit to how many particles appear in the screen per repulsor each frame
- if (particle_count > REPULSOR_MAXIMUM_PARTICLES_PER_FRAME) {
- particle_count = REPULSOR_MAXIMUM_PARTICLES_PER_FRAME;
- }
- for (int i = 0; i < particle_count; i++) {
- float dist = repulseRadius * (float) getBiasedRandom(REPULSOR_PARTICLE_DISTRIBUTION_BIAS, 0, 1);
- float angle = (float) Math.random() * 360f;
- Vector2f randPoint = MathUtils.getPointOnCircumference(shipLoc, dist, angle);
- float randSize = MathUtils.getRandomNumberInRange(REPULSOR_SIZE_FACTOR_MIN * repulseRadius, REPULSOR_SIZE_FACTOR_MAX * repulseRadius);
- if (randSize < MIN_REPULSOR_PARTICLE_SIZE) {
- randSize = MIN_REPULSOR_PARTICLE_SIZE;
- }
- Vector2f velocity = MathUtils.getPointOnCircumference(shipVec, (REPULSOR_SPEED_FACTOR * dist), angle + REPULSOR_ORBIT_DIR * REPULSOR_VELOCITY_ANGLE_CONSTANT);
- float randDur = 0.1f + MathUtils.getRandomNumberInRange(MIN_REPULSOR_PARTICLE_DURATION, MAX_REPULSOR_PARTICLE_DURATION);
- int yelVal = (int) (MIN_REPULSOR_COLOR_YELLOW + Math.random() * (MAX_REPULSOR_COLOR_YELLOW - MIN_REPULSOR_COLOR_YELLOW));
- Color color = new Color(0, yelVal, 255, 255);
- ///
- //activeEngine.addSmoothParticle( randPoint, velocity, randSize, 1f, randDur, color );
- activeEngine.addHitParticle(randPoint, velocity, randSize, 1f, randDur, color);
- }
- List<ShipAPI> nearbyEnemies = CombatUtils.getShipsWithinRange(shipLoc, repulseRadius);//List of enemies to push back, smoothly
- for (ShipAPI thisEnemy : nearbyEnemies) {
- //Don't push phased ships.
- ShipSystemAPI cloak = thisEnemy.getPhaseCloak();
- if (cloak != null && cloak.isActive()) {
- continue; // phase ship, skip it
- }
- push(ship, thisEnemy); // push it
- //Test code here
- //activeEngine.addFloatingText(thisEnemyLoc, "Repulsed with " + pushVec.x + pushVec.y + " force!", 20f, Color.BLUE, ship, 1f, 0f);
- }
- List<CombatEntityAPI> nearbyAsteroids = CombatUtils.getAsteroidsWithinRange(shipLoc, repulseRadius); //List of enemies to push back, smoothly
- for (CombatEntityAPI asteroid : nearbyAsteroids) {
- push(ship, asteroid); // push it always
- }
- //Iterates through nearby enemy projectiles and reverses their course, "repulsing" them.
- //In theory, two groups with Repulsors active could ping-pong shots back and forth at one another nearly forever...
- //In reality, the time intervals don't allow for it.
- int numRepulseParticles = 0;
- for (DamagingProjectileAPI thisProj : activeEngine.getProjectiles()) {
- if (thisProj.getOwner() != ship.getOwner() && Math.random() > 0.2f)//If not ours and if luck favors us, then...
- {
- //Get the projectile to be reversed's vital stats, including the inverse of its velocity (to send it right back where it came from)
- Vector2f thisProjLoc = thisProj.getLocation();
- Vector2f thisProjVel = thisProj.getVelocity();
- if (MathUtils.getDistanceSquared(shipLoc, thisProjLoc) > (repulseRadius * repulseRadius)) {
- continue;
- }
- if (numRepulseParticles < FEEDBACK_PARTICLE_MAX_PER_REPULSE) {
- numRepulseParticles++;
- // Creates a handy feedback effect
- int yelVal = (int) (MIN_REPULSOR_COLOR_YELLOW + Math.random() * (MAX_REPULSOR_COLOR_YELLOW - MIN_REPULSOR_COLOR_YELLOW));
- Color color = new Color(0, yelVal, 255, 255);
- float scaleFactor;
- if (thisProj.getDamageType() == DamageType.FRAGMENTATION) {
- scaleFactor = (float) Math.sqrt(thisProj.getDamageAmount() * 0.25f);
- } else {
- scaleFactor = (float) Math.sqrt(thisProj.getDamageAmount() * 1f);
- }
- scaleFactor = Math.min(scaleFactor, 40);
- activeEngine.addHitParticle(thisProjLoc, ship.getVelocity(),
- FEEDBACK_PARTICLE_SIZEFACTOR * scaleFactor,
- FEEDBACK_PARTICLE_BRIGHTNESS,
- FEEDBACK_PARTICLE_DURATION,
- color);
- if (Math.random() < 0.2f + thisProj.getCollisionRadius() / 10f) {
- Global.getSoundPlayer().playSound(FEEDBACK_SOUND_ID, (float) Math.random() * 0.2f + 0.9f, 0.7f + scaleFactor / 30f, thisProjLoc, new Vector2f());
- }
- }
- // Reverse projectile with a 10 degree margin of error
- float returnAngle = MathUtils.clampAngle(VectorUtils.getFacing(thisProjVel) + MathUtils.getRandomNumberInRange(170f, 190f));
- thisProjVel.set(MathUtils.getPointOnCircumference(null, thisProjVel.length() * 1.3f, returnAngle));
- thisProj.setFacing(returnAngle);
- thisProj.setOwner(ship.getOwner());
- thisProj.setSource(ship);
- }
- //activeEngine.addFloatingText(thisProjLoc, "Repulsed with " + pushVec.x + pushVec.y + " force!", 20f, Color.BLUE, ship, 1f, 0f);
- }
- } else {
- // If null or not a ship, it gets removed.
- iter.remove();
- }
- }
- }
- Random tRandom = new Random();
- private double getBiasedRandom(double bias, double min, double max) {
- double centered_depth_perc = 0.3;
- double centered_depth_abs = (max - min) * centered_depth_perc;
- double center = 0.5;
- double rndBiased;
- double rndCentered = center + tRandom.nextGaussian() * centered_depth_abs; // generate centered random number.
- if (rndCentered >= center) {
- rndBiased = (rndCentered - center) * (max - bias) + bias;
- } else {
- rndBiased = bias - (center - rndCentered) * (bias - min);
- }
- // the following two tests will be as more important as centered_depth_perc
- // get bigger.
- if (rndBiased > max) {
- rndBiased = max;
- }
- if (rndBiased < min) {
- rndBiased = min;
- }
- return rndBiased;
- }
- private void push(CombatEntityAPI source, CombatEntityAPI target) {
- if (source.getOwner() == target.getOwner()) {
- return;
- }
- Vector2f source_loc = source.getLocation();
- Vector2f target_loc = target.getLocation();
- Vector2f pushVec = new Vector2f(target_loc.x - source_loc.x, target_loc.y - source_loc.y);//Get the vector going from A to B
- float magnitude = (1f / pushVec.lengthSquared()); //Get the magnitude of the vector (usually very small)
- float mass = Math.max(1f, target.getMass());
- magnitude /= mass;
- pushVec.x *= magnitude * 1000000f;
- pushVec.y *= magnitude * 1000000f;
- Vector2f enemyVel = target.getVelocity(); //Get the velocity of the ship, and add the new vector to it.
- enemyVel.x += pushVec.x;
- enemyVel.y += pushVec.y;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement