001package com.fs.starfarer.api.impl.combat;
002
003import java.util.Iterator;
004
005import java.awt.Color;
006
007import org.lwjgl.util.vector.Vector2f;
008
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.combat.CollisionClass;
011import com.fs.starfarer.api.combat.CombatEngineAPI;
012import com.fs.starfarer.api.combat.CombatEntityAPI;
013import com.fs.starfarer.api.combat.DamageType;
014import com.fs.starfarer.api.combat.DamagingProjectileAPI;
015import com.fs.starfarer.api.combat.EmpArcEntityAPI;
016import com.fs.starfarer.api.combat.MissileAPI;
017import com.fs.starfarer.api.combat.OnFireEffectPlugin;
018import com.fs.starfarer.api.combat.ShipAPI;
019import com.fs.starfarer.api.combat.WeaponAPI;
020import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
021import com.fs.starfarer.api.impl.campaign.ids.Stats;
022import com.fs.starfarer.api.util.Misc;
023
024/**
025 */
026public class ShockRepeaterOnFireEffect implements OnFireEffectPlugin {
027
028        public static float ARC = 30f;
029        
030        public void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
031                //ARC = 30f;
032                float emp = projectile.getEmpAmount();
033                float dam = projectile.getDamageAmount();
034        
035                CombatEntityAPI target = findTarget(projectile, weapon, engine);
036                float thickness = 20f;
037                float coreWidthMult = 0.67f;
038                Color color = weapon.getSpec().getGlowColor();
039                if (target != null) {
040                        EmpArcEntityAPI arc = engine.spawnEmpArc(projectile.getSource(), projectile.getLocation(), weapon.getShip(),
041                                           target,
042                                           DamageType.ENERGY, 
043                                           dam,
044                                           emp, // emp 
045                                           100000f, // max range 
046                                           "shock_repeater_emp_impact",
047                                           thickness, // thickness
048                                           color,
049                                           new Color(255,255,255,255)
050                                           );
051                        arc.setCoreWidthOverride(thickness * coreWidthMult);
052                        arc.setSingleFlickerMode();
053                } else {
054                        Vector2f from = new Vector2f(projectile.getLocation());
055                        Vector2f to = pickNoTargetDest(projectile, weapon, engine);
056                        EmpArcEntityAPI arc = engine.spawnEmpArcVisual(from, weapon.getShip(), to, weapon.getShip(), thickness, color, Color.white);
057                        arc.setCoreWidthOverride(thickness * coreWidthMult);
058                        arc.setSingleFlickerMode();
059                        //Global.getSoundPlayer().playSound("shock_repeater_emp_impact", 1f, 1f, to, new Vector2f());
060                }
061        }
062        
063        public Vector2f pickNoTargetDest(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
064                float spread = 50f;
065                float range = weapon.getRange() - spread;
066                Vector2f from = projectile.getLocation();
067                Vector2f dir = Misc.getUnitVectorAtDegreeAngle(weapon.getCurrAngle());
068                dir.scale(range);
069                Vector2f.add(from, dir, dir);
070                dir = Misc.getPointWithinRadius(dir, spread);
071                return dir;
072        }
073        
074        public CombatEntityAPI findTarget(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
075                float range = weapon.getRange();
076                Vector2f from = projectile.getLocation();
077                
078                Iterator<Object> iter = Global.getCombatEngine().getAllObjectGrid().getCheckIterator(from,
079                                                                                                                                                        range * 2f, range * 2f);
080                int owner = weapon.getShip().getOwner();
081                CombatEntityAPI best = null;
082                float minScore = Float.MAX_VALUE;
083                
084                ShipAPI ship = weapon.getShip();
085                boolean ignoreFlares = ship != null && ship.getMutableStats().getDynamic().getValue(Stats.PD_IGNORES_FLARES, 0) >= 1;
086                ignoreFlares |= weapon.hasAIHint(AIHints.IGNORES_FLARES);
087                
088                while (iter.hasNext()) {
089                        Object o = iter.next();
090                        if (!(o instanceof MissileAPI) &&
091                                        //!(o instanceof CombatAsteroidAPI) &&
092                                        !(o instanceof ShipAPI)) continue;
093                        CombatEntityAPI other = (CombatEntityAPI) o;
094                        if (other.getOwner() == owner) continue;
095                        
096                        if (other instanceof ShipAPI) {
097                                ShipAPI otherShip = (ShipAPI) other;
098                                if (otherShip.isHulk()) continue;
099                                //if (!otherShip.isAlive()) continue;
100                                if (otherShip.isPhased()) continue;
101                                if (!otherShip.isTargetable()) continue;
102                        }
103                        
104                        if (other.getCollisionClass() == CollisionClass.NONE) continue;
105                        
106                        if (ignoreFlares && other instanceof MissileAPI) {
107                                MissileAPI missile = (MissileAPI) other;
108                                if (missile.isFlare()) continue;
109                        }
110
111                        float radius = Misc.getTargetingRadius(from, other, false);
112                        float dist = Misc.getDistance(from, other.getLocation()) - radius;
113                        if (dist > range) continue;
114                        
115                        if (!Misc.isInArc(weapon.getCurrAngle(), ARC, from, other.getLocation())) continue;
116                        
117                        //float angleTo = Misc.getAngleInDegrees(from, other.getLocation());
118                        //float score = Misc.getAngleDiff(weapon.getCurrAngle(), angleTo);
119                        float score = dist;
120                        
121                        if (score < minScore) {
122                                minScore = score;
123                                best = other;
124                        }
125                }
126                return best;
127        }
128
129}