001package com.fs.starfarer.api.impl.combat.dweller;
002
003import java.util.Iterator;
004import java.util.List;
005
006import java.awt.Color;
007
008import org.lwjgl.util.vector.Vector2f;
009
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.combat.CollisionClass;
012import com.fs.starfarer.api.combat.CombatEngineAPI;
013import com.fs.starfarer.api.combat.CombatEntityAPI;
014import com.fs.starfarer.api.combat.DamageType;
015import com.fs.starfarer.api.combat.DamagingProjectileAPI;
016import com.fs.starfarer.api.combat.EmpArcEntityAPI;
017import com.fs.starfarer.api.combat.EmpArcEntityAPI.EmpArcParams;
018import com.fs.starfarer.api.combat.EveryFrameWeaponEffectPlugin;
019import com.fs.starfarer.api.combat.MissileAPI;
020import com.fs.starfarer.api.combat.OnFireEffectPlugin;
021import com.fs.starfarer.api.combat.ShipAPI;
022import com.fs.starfarer.api.combat.WeaponAPI;
023import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
024import com.fs.starfarer.api.impl.campaign.ids.Stats;
025import com.fs.starfarer.api.impl.combat.RealityDisruptorChargeGlow;
026import com.fs.starfarer.api.impl.combat.RealityDisruptorChargeGlow.EMPArcHitType;
027import com.fs.starfarer.api.impl.combat.RealityDisruptorChargeGlow.RDRepairRateDebuff;
028import com.fs.starfarer.api.util.Misc;
029
030/**
031 */
032public class InimicalEmanationOnFireEffect implements OnFireEffectPlugin, EveryFrameWeaponEffectPlugin {
033
034        public static float EXTRA_ARC = 30f;
035        public static float REPAIR_RATE_DEBUFF_DUR = 5f;
036        
037//      public static String PREV_INIMICAL_EMANATION_FIRE_TIMESTAMP_KEY = "prev_inimical_emanation_fire_timestamp_key";
038//      public static float EXTRA_RANGE_SYMPATHETIC = 300f;
039        
040
041        protected float extraRangeOnNextFire = 0f;
042        
043        @Override
044        public void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon) {
045//              Float firedPrev = (Float) engine.getCustomData().get(PREV_INIMICAL_EMANATION_FIRE_TIMESTAMP_KEY);
046//              if (firedPrev == null) firedPrev = -1000f;
047//              
048//              float currTimestamp = engine.getTotalElapsedTime(false);
049//              float sinceFired = currTimestamp - firedPrev;
050//              if (sinceFired < 0.1f && (float) Math.random() > 0.85f) {
051//                      extraRangeOnNextFire = EXTRA_RANGE_SYMPATHETIC;
052//                      weapon.setForceFireOneFrame(true);
053//              }
054        }
055        
056        public void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
057                ShipAPI ship = weapon.getShip();
058                if (ship == null) return;
059                
060                float emp = projectile.getEmpAmount();
061                float dam = projectile.getDamageAmount();
062                
063                CombatEntityAPI target = findTarget(projectile, weapon, engine);
064                
065                Vector2f noTargetDest = null;
066                if (target == null) noTargetDest = pickNoTargetDest(projectile, weapon, engine);
067                
068                Vector2f towards = noTargetDest;
069                if (target != null) towards = target.getLocation();
070                
071                float thickness = 30f;
072                Color color = weapon.getSpec().getGlowColor();
073                Color coreColor = Color.white;
074                coreColor = Misc.zeroColor;
075                coreColor = color;
076                
077                
078                color = new Color(255,0,30,255);
079                //coreColor = new Color(255,10,50,155);
080                coreColor = new Color(255,10,255,255);
081//              coreColor = new Color(255,0,30,255);
082//              color = new Color(255,10,255,255);
083                
084                //color = RiftLightningEffect.RIFT_LIGHTNING_COLOR;
085                color = DwellerShroud.SHROUD_GLOW_COLOR;
086                coreColor = color;
087//              coreColor = Misc.interpolateColor(color, Color.white, 0.25f);
088//              coreColor = Color.white;
089                
090                float coreWidthMult = 1f;
091                
092                
093                Vector2f from = projectile.getLocation();
094                DwellerShroud shroud = DwellerShroud.getShroudFor(ship);
095                if (shroud != null) {
096                        float angle = Misc.getAngleInDegrees(ship.getLocation(), towards);
097                        from = Misc.getUnitVectorAtDegreeAngle(angle + 90f - 180f * (float) Math.random());
098                        from.scale((0.5f + (float) Math.random() * 0.25f) * shroud.getShroudParams().maxOffset);
099                        Vector2f.add(ship.getLocation(), from, from);
100                }
101                
102                EmpArcParams params = new EmpArcParams();
103                //params.segmentLengthMult = 10000f;
104                params.segmentLengthMult = 4f;
105                
106//              params.maxZigZagMult = 0f;
107//              params.zigZagReductionFactor = 1f;
108                
109                params.maxZigZagMult = 0.25f;
110                params.zigZagReductionFactor = 1f;
111                
112                //params.glowColorOverride = new Color(255,10,155,255);
113                
114                //params.zigZagReductionFactor = 0.25f;
115                //params.maxZigZagMult = 0f;
116                //params.flickerRateMult = 0.75f;
117//              params.flickerRateMult = 1f;
118//              params.flickerRateMult = 0.75f;
119                params.flickerRateMult = 0.75f + 0.25f * (float) Math.random();
120                
121                params.fadeOutDist = 150f;
122                params.minFadeOutMult = 5f;
123                
124                params.glowSizeMult = 0.5f;
125                //params.glowAlphaMult = 0.5f;
126                //params.flamesOutMissiles = false;
127                
128//              params.movementDurOverride = 0.1f;
129//              params.flickerRateMult = 0.5f;
130//              params.glowSizeMult = 1f;
131//              params.brightSpotFadeFraction = 0.1f;
132//              params.brightSpotFullFraction = 0.9f;
133                
134//              params.maxZigZagMult = 1f;
135//              params.zigZagReductionFactor = 0f;
136//              params.flickerRateMult = 0.25f;
137                
138                if (target != null) {
139                        EmpArcEntityAPI arc = engine.spawnEmpArc(ship, from, ship,
140                                           target,
141                                           DamageType.ENERGY, 
142                                           dam,
143                                           emp, // emp 
144                                           100000f, // max range 
145                                           "inimical_emanation_impact",
146                                           thickness, // thickness
147                                           color,
148                                           coreColor,
149                                           params
150                                           );
151                        arc.setCoreWidthOverride(thickness * coreWidthMult);
152                        arc.setSingleFlickerMode();
153                        arc.setRenderGlowAtStart(false);
154                        if (shroud != null) {
155                                arc.setFadedOutAtStart(true);
156                        }
157                        arc.setWarping(0.2f);
158                        
159                        if (target instanceof ShipAPI && !arc.isShieldHit()) {
160                                ShipAPI s = (ShipAPI) target;
161                                List<RDRepairRateDebuff> listeners = s.getListeners(RDRepairRateDebuff.class);
162                                if (listeners.isEmpty()) {
163                                        s.addListener(new RDRepairRateDebuff(s, REPAIR_RATE_DEBUFF_DUR));
164                                } else {
165                                        listeners.get(0).resetDur(REPAIR_RATE_DEBUFF_DUR);
166                                }
167                        }
168                        
169                        
170                        if (arc.getTargetLocation() != null) {
171                                RealityDisruptorChargeGlow.spawnEMPParticles(EMPArcHitType.INIMICAL_EMANATION, null, arc.getTargetLocation(), target);
172                        }
173                        
174                } else {
175                        Vector2f to = noTargetDest;
176                        EmpArcEntityAPI arc = engine.spawnEmpArcVisual(from, ship, to, ship, thickness, color, coreColor, params);
177                        arc.setCoreWidthOverride(thickness * coreWidthMult);
178                        arc.setSingleFlickerMode();
179                        arc.setRenderGlowAtStart(false);
180                        if (shroud != null) {
181                                arc.setFadedOutAtStart(true);
182                        }
183                        arc.setWarping(0.2f);
184                        
185                        RealityDisruptorChargeGlow.spawnEMPParticles(EMPArcHitType.INIMICAL_EMANATION, null, to, ship);
186                }
187                
188//              float fireTimestamp = engine.getTotalElapsedTime(false);
189//              engine.getCustomData().put(PREV_INIMICAL_EMANATION_FIRE_TIMESTAMP_KEY, Float.valueOf(fireTimestamp));
190        }
191        
192        public Vector2f pickNoTargetDest(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
193                float spread = 50f;
194                float range = Math.min(weapon.getRange() - spread, 300f);
195                Vector2f from = projectile.getLocation();
196                Vector2f dir = Misc.getUnitVectorAtDegreeAngle(weapon.getCurrAngle() + (EXTRA_ARC/2f - EXTRA_ARC * (float) Math.random()));
197                dir.scale(range);
198                Vector2f.add(from, dir, dir);
199                dir = Misc.getPointWithinRadius(dir, spread);
200                return dir;
201        }
202        
203        public CombatEntityAPI findTarget(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
204                float range = weapon.getRange() + 50f + extraRangeOnNextFire;
205                extraRangeOnNextFire = 0f;
206                Vector2f from = projectile.getLocation();
207                
208                Iterator<Object> iter = Global.getCombatEngine().getAllObjectGrid().getCheckIterator(from,
209                                                                                                                                                        range * 2f, range * 2f);
210                int owner = weapon.getShip().getOwner();
211                CombatEntityAPI best = null;
212                float minScore = Float.MAX_VALUE;
213                
214                ShipAPI ship = weapon.getShip();
215                boolean ignoreFlares = ship != null && ship.getMutableStats().getDynamic().getValue(Stats.PD_IGNORES_FLARES, 0) >= 1;
216                ignoreFlares |= weapon.hasAIHint(AIHints.IGNORES_FLARES);
217                
218                boolean phaseMode = true;
219                
220                while (iter.hasNext()) {
221                        Object o = iter.next();
222                        if (!(o instanceof MissileAPI) &&
223                                        //!(o instanceof CombatAsteroidAPI) &&
224                                        !(o instanceof ShipAPI)) continue;
225                        CombatEntityAPI other = (CombatEntityAPI) o;
226                        if (other.getOwner() == owner) continue;
227                        
228                        boolean phaseHit = false;
229                        if (other instanceof ShipAPI) {
230                                ShipAPI otherShip = (ShipAPI) other;
231                                if (otherShip.isHulk()) continue;
232                                //if (!otherShip.isAlive()) continue;
233                                if (otherShip.isPhased()) {
234                                        if (phaseMode) {
235                                                phaseHit = true;
236                                        } else {
237                                                continue;
238                                        }
239                                }
240                                if (!otherShip.isTargetable()) continue;
241                        }
242                        
243                        if (!phaseHit && other.getCollisionClass() == CollisionClass.NONE) continue;
244                        
245                        if (ignoreFlares && other instanceof MissileAPI) {
246                                MissileAPI missile = (MissileAPI) other;
247                                if (missile.isFlare()) continue;
248                        }
249
250                        float radius = Misc.getTargetingRadius(from, other, false);
251                        float dist = Misc.getDistance(from, other.getLocation()) - radius;
252                        if (dist > range) continue;
253                        
254                        if (!Misc.isInArc(weapon.getCurrAngle(), EXTRA_ARC, from, other.getLocation())) continue;
255                        
256                        float score = dist;
257                        
258                        if (score < minScore) {
259                                minScore = score;
260                                best = other;
261                        }
262                }
263                return best;
264        }
265
266}