///////////////////////GENERIC EXPLOSION GENERATOR AND AOE SIMULATION
///////////////////////REQUIRES LAZYLIB
package data.scripts;
import java.awt.Color;
import org.lwjgl.util.vector.Vector2f;
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.OnHitEffectPlugin;
import com.fs.starfarer.api.combat.ShipAPI;
import com.fs.starfarer.api.combat.WeaponAPI;
import java.util.List;
import java.util.Iterator;
import org.lazywizard.lazylib.MathUtils;
import org.lazywizard.lazylib.CollisionUtils;
import org.lazywizard.lazylib.combat.*;
public class ExplosiveOnHitEffectWithAOE implements OnHitEffectPlugin {
public void onHit(DamagingProjectileAPI projectile, CombatEntityAPI target,
Vector2f point, boolean shieldHit, CombatEngineAPI engine) {
float emp = projectile.getEmpAmount();
float dam = projectile.getDamageAmount();
WeaponAPI weapon = projectile.getWeapon();
DamageType damType = weapon.getDamageType();
float aoeToCheck = Math.max(dam / 10f, 20f);//Checks an area equal to damage / 10, with a floor of 20 (anything lower than that isn't worth doing, imo, but you may want to put an upper cap on really huge-damage weapons); can be adjusted to whatever you want
float aoeMult = 0.5f;//This is our multiplier against damage for distant targets, for balance purposes.
//AOE CODE
//This code searches first for nearby Ships, then for nearby non-ship entities, and applies damage to them over the AOE.
//When it checks for nearby ships, if it finds any it gets a valid collision (or not) by doing a ray-test...
//Which keeps things easy (don't thank me, thank Alex / LazyWizard)
//We don't need that (fairly expensive) check for nearby missiles, so we don't bother.
//If the checks come up with anything, then it gets damaged, in this case by half of the base damage.
List nearbyEnemies = CombatUtils.getShipsWithinRange(point, aoeToCheck, true);
for(Iterator iterMe = nearbyEnemies.iterator(); iterMe.hasNext();)
{
CombatEntityAPI targEnt = (CombatEntityAPI) iterMe.next();
if(targEnt != target && (targEnt.getOwner() != ((CombatEntityAPI) projectile.getSource()).getOwner()))//No double hits or friendly fire.
{
Vector2f targLoc = targEnt.getLocation();
//Try to get a valid collision point between our explosion's point source and the Entity.
Vector2f colPoint = CollisionUtils.getCollisionPoint(point, targLoc, targEnt);
//If we can't get a good collision point, use the center of the target Entity. This is potentially a balance issue (hits all going to one armor cell are pretty OP lol), but this case mainly covers little teeny drones and suchlike that should be registering hits from giant explosions nearby, but often don't, for whatever reason. Bigger things rarely fail, so it usually works out.
if(colPoint == null) colPoint = targLoc;
if(colPoint != null)//Must check this, getCollisionPoint returns null fairly frequently and that's a wrap
{
engine.applyDamage(
targEnt, //enemy Entity
colPoint, //Our 2D vector to the exact world-position of the collision
dam * aoeMult, //DPS modified by the damage multiplier
damType, //Using the damage type here, so that Kinetic / Explosive / Fragmentation AOE works.
emp * aoeMult, //EMP
false, //Does not bypass shields.
false, //Does not do Soft Flux damage (unless you want it to for some strange reason)
projectile.getSource() //Who owns this projectile?
);
//This is just for testing purposes- shows a blue dot if, when and where hits occur. Handy for testing balance.
/*
for(int i = 0; i < 6; i++)
{
engine.addHitParticle(colPoint, new Vector2f(MathUtils.getRandomNumberInRange(-5,5), MathUtils.getRandomNumberInRange(-5,5)), MathUtils.getRandomNumberInRange(25,50), 1f, 100f, new Color(0,0,255,255));
}*/
}
}
}
//Simpler task for missiles- we don't need an intersection with Hulls to get a valid armor location.
nearbyEnemies = CombatUtils.getMissilesWithinRange(point, aoeToCheck, true);
for(Iterator iterMe = nearbyEnemies.iterator(); iterMe.hasNext();)
{
CombatEntityAPI targEnt = (CombatEntityAPI) iterMe.next();
if(targEnt != target && (targEnt.getOwner() != ((CombatEntityAPI) projectile.getSource()).getOwner()))//No double hits or friendly fire.
{
Vector2f targLoc = targEnt.getLocation();
engine.applyDamage(
targEnt, //enemy Entity
targLoc, //Our 2D vector to the exact world-position of the collision
dam * aoeMult, //DPS modified by the damage multiplier
damType, //Using the damage type here, so that Kinetic / Explosive / Fragmentation AOE works.
emp * aoeMult, //EMP
false, //Does not bypass shields.
false, //Does not do Soft Flux damage (unless you want it to for some strange reason)
projectile.getSource() //Who owns this projectile?
);
}
}
//EXPLOSION BITZ
//This code auto-magically builds a reasonably-cool generic explosion, based on weapon damage.
//There isn't much code that's expensive here and the game does auto-cull particles, so this can be made more complex if you want. Just be careful about how many particles you create per event, since that's a linear cost (i.e., if you stick this on a Vulcan-type weapon, keep the total count low, low or re-write that part).
int repeat = Math.max(5,(int) ((dam / 60f)));
int repeatTwo = repeat / 3;
//This bit makes backdrop glows show up fairly briefly behind our main explosion.
//Just one particle per repeat, but it costs a lot of operations to built it.
for(int i = 0; i < repeatTwo; i++)
{
Vector2f randPoint = MathUtils.getRandomPointInCircle(point,dam/35f);
float randSize = MathUtils.getRandomNumberInRange(dam/25f,Math.max(dam / 20f,15f));
Vector2f randVec = new Vector2f(MathUtils.getRandomNumberInRange(-dam / 50f ,dam / 50f),MathUtils.getRandomNumberInRange(-dam / 50f ,dam / 50f));
float randDur = 0.1f + MathUtils.getRandomNumberInRange(0.0f,0.3f);
int yelVal = (int) (Math.random() * 200f + 32f);
int randTrans = (int) MathUtils.getRandomNumberInRange(64f,128f);
engine.addSmoothParticle(randPoint, randVec, randSize, 1f, randDur, new Color(255,yelVal,0,randTrans));
}
//Main explosion, fast & slow fires and smoke at the end.
//Six particles per repeat, min 30.
for(int i = 0; i < repeat; i++)
{
int yelVal = (int) (Math.random() * 128f + 64f);
Vector2f randPoint = MathUtils.getRandomPointInCircle(point,dam/100f);
//Random Vectors, in order of speed; generally, we need smoke and central poof to be slower than others
Vector2f randVecFast = new Vector2f(MathUtils.getRandomNumberInRange(-30f - dam / 2f ,30f + dam / 2f),MathUtils.getRandomNumberInRange(-30f - dam / 2f ,30f + dam / 2f));
Vector2f randVecFastTwo = new Vector2f(MathUtils.getRandomNumberInRange(-30f - dam / 2f ,30f + dam / 2f),MathUtils.getRandomNumberInRange(-30f - dam / 2f ,30f + dam / 2f));
Vector2f randVec = new Vector2f(MathUtils.getRandomNumberInRange(-dam / 25f ,dam / 25f),MathUtils.getRandomNumberInRange(-dam / 25f ,dam / 25f));
Vector2f randVecTwo = new Vector2f(MathUtils.getRandomNumberInRange(-dam / 35f ,dam / 35f),MathUtils.getRandomNumberInRange(-dam / 35f,dam / 35f));
Vector2f randVecThree = new Vector2f(MathUtils.getRandomNumberInRange(-dam / 40f ,dam / 40f),MathUtils.getRandomNumberInRange(-dam / 40f,dam / 40f));
float randSize = MathUtils.getRandomNumberInRange(10f,Math.max(dam / 50f,15f));
float randSizeTwo = MathUtils.getRandomNumberInRange(5f,10f);
float randDur = 1f + MathUtils.getRandomNumberInRange(-0.5f,3f);
float randDurTwo = MathUtils.getRandomNumberInRange(0.5f,1f);
int randTrans = (int) MathUtils.getRandomNumberInRange(32f,200f);
int randGray = (int) MathUtils.getRandomNumberInRange(32f,64f);
engine.addHitParticle(point, randVecFast, randSizeTwo, 1f, randDurTwo * 0.5f, new Color(255,yelVal + 64,0,randTrans + 55));
engine.addHitParticle(point, randVecFastTwo, randSizeTwo, 1f, randDurTwo * 0.65f, new Color(255,yelVal + 64,0,randTrans + 55));
engine.addHitParticle(point, randVec, randSize, 1f, randDurTwo, new Color(255,yelVal-64,0,randTrans));
engine.addHitParticle(point, randVecTwo, randSize, 1f, randDurTwo * 0.75f, new Color(255,yelVal-32,0,randTrans));
engine.addHitParticle(point, randVecThree, randSize, 1f, randDurTwo * 0.5f, new Color(255,yelVal,0,randTrans));
engine.addSmokeParticle(point, randVecThree, MathUtils.getRandomNumberInRange(dam / 100f,dam / 50f), MathUtils.getRandomNumberInRange(0.5f,1f), randDur, new Color(randGray,randGray,randGray,randTrans));
}
}
}