001package com.fs.starfarer.api.impl.combat;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.Collections;
006import java.util.List;
007
008import com.fs.starfarer.api.Global;
009import com.fs.starfarer.api.combat.CombatEngineAPI;
010import com.fs.starfarer.api.combat.MutableShipStatsAPI;
011import com.fs.starfarer.api.combat.ShipAPI;
012import com.fs.starfarer.api.combat.ShipEngineControllerAPI;
013import com.fs.starfarer.api.combat.ShipSystemAPI;
014import com.fs.starfarer.api.combat.ShipAPI.HullSize;
015import com.fs.starfarer.api.combat.ShipEngineControllerAPI.ShipEngineAPI;
016import com.fs.starfarer.api.combat.ShipSystemAPI.SystemState;
017import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags;
018import com.fs.starfarer.api.util.Misc;
019import com.fs.starfarer.api.util.Misc.FindShipFilter;
020
021public class InterdictorArrayStats extends BaseShipSystemScript {
022        public static final Object SHIP_KEY = new Object();
023        public static final Object TARGET_KEY = new Object();
024        
025        public static final float WING_EFFECT_RANGE = 200f;
026        
027        public static final float RANGE = 1000f;
028        public static final Color EFFECT_COLOR = new Color(100,165,255,75);
029        
030        
031        public static class TargetData {
032                public ShipAPI target;
033                public float sinceLastAfterimage = 0f;
034                public boolean lastAbove = false;
035                public TargetData(ShipAPI target) {
036                        this.target = target;
037                }
038        }
039        
040        public void apply(MutableShipStatsAPI stats, final String id, State state, float effectLevel) {
041                ShipAPI ship = null;
042                if (stats.getEntity() instanceof ShipAPI) {
043                        ship = (ShipAPI) stats.getEntity();
044                } else {
045                        return;
046                }
047                
048                final String targetDataKey = ship.getId() + "_interdictor_target_data";
049                
050                Object targetDataObj = Global.getCombatEngine().getCustomData().get(targetDataKey); 
051                if (state == State.IN && targetDataObj == null) {
052                        ShipAPI target = findTarget(ship);
053                        Global.getCombatEngine().getCustomData().put(targetDataKey, new TargetData(target));
054                } else if (state == State.IDLE && targetDataObj != null) {
055                        Global.getCombatEngine().getCustomData().remove(targetDataKey);
056                }
057                if (targetDataObj == null || ((TargetData) targetDataObj).target == null) return;
058                
059                final TargetData targetData = (TargetData) targetDataObj;
060                
061                //ShipAPI target = targetData.target;
062                List<ShipAPI> targets = new ArrayList<ShipAPI>();
063                if (targetData.target.isFighter() || targetData.target.isDrone()) {
064                        CombatEngineAPI engine = Global.getCombatEngine();
065                        List<ShipAPI> ships = engine.getShips();
066                        for (ShipAPI other : ships) {
067                                if (other.isShuttlePod()) continue;
068                                if (other.isHulk()) continue;
069                                if (!other.isDrone() && !other.isFighter()) continue;
070                                if (other.getOriginalOwner() != targetData.target.getOriginalOwner()) continue;
071                                
072                                float dist = Misc.getDistance(other.getLocation(), targetData.target.getLocation());
073                                if (dist > WING_EFFECT_RANGE) continue;
074                                
075                                targets.add(other);
076                        }
077                } else {
078                        targets.add(targetData.target);
079                }
080                
081                boolean first = true;
082                for (ShipAPI target : targets) {
083                        if (effectLevel >= 1) {
084                                Color color = getEffectColor(target);
085                                color = Misc.setAlpha(color, 255);
086
087                                if (first) {
088                                        if (target.getFluxTracker().showFloaty() || 
089                                                        ship == Global.getCombatEngine().getPlayerShip() ||
090                                                        target == Global.getCombatEngine().getPlayerShip()) {
091                                                target.getFluxTracker().showOverloadFloatyIfNeeded("Drive Interdicted!", color, 4f, true);
092                                        }
093                                        first = false;
094                                }
095
096                                ShipEngineControllerAPI ec = target.getEngineController();
097                                float limit = ec.getFlameoutFraction();
098                                if (target.isDrone() || target.isFighter()) {
099                                        limit = 1f;
100                                }
101
102                                float disabledSoFar = 0f;
103                                boolean disabledAnEngine = false;
104                                List<ShipEngineAPI> engines = new ArrayList<ShipEngineAPI>(ec.getShipEngines());
105                                Collections.shuffle(engines);
106
107                                for (ShipEngineAPI engine : engines) {
108                                        if (engine.isDisabled()) continue;
109                                        float contrib = engine.getContribution();
110                                        if (disabledSoFar + contrib <= limit) {
111                                                engine.disable();
112                                                disabledSoFar += contrib;
113                                                disabledAnEngine = true;
114                                        }
115                                }
116                                if (!disabledAnEngine) {
117                                        for (ShipEngineAPI engine : engines) {
118                                                if (engine.isDisabled()) continue;
119                                                engine.disable();
120                                                break;
121                                        }
122                                }
123                                ec.computeEffectiveStats(ship == Global.getCombatEngine().getPlayerShip());
124                        }
125
126                        if (effectLevel > 0) {
127                                float jitterLevel = effectLevel;
128                                float maxRangeBonus = 20f + target.getCollisionRadius() * 0.25f;
129                                float jitterRangeBonus = jitterLevel * maxRangeBonus;
130                                if (state == State.OUT) {
131                                        jitterRangeBonus = maxRangeBonus + (1f - jitterLevel) * maxRangeBonus;
132                                }
133                                target.setJitter(this,
134                                                //target.getSpriteAPI().getAverageColor(),
135                                                getEffectColor(target),
136                                                jitterLevel, 6, 0f, 0 + jitterRangeBonus);
137
138                                if (first) {
139                                        ship.setJitter(this,
140                                                        //target.getSpriteAPI().getAverageColor(),
141                                                        getEffectColor(targetData.target),
142                                                        jitterLevel, 6, 0f, 0 + jitterRangeBonus);
143                                }
144                        }
145                }
146        }
147        
148
149        protected Color getEffectColor(ShipAPI ship) {
150                if (ship.getEngineController().getShipEngines().isEmpty()) {
151                        return EFFECT_COLOR;
152                }
153                return Misc.setAlpha(ship.getEngineController().getShipEngines().get(0).getEngineColor(), EFFECT_COLOR.getAlpha());
154        }
155        
156        
157        public void unapply(MutableShipStatsAPI stats, String id) {
158                
159        }
160        
161        protected ShipAPI findTarget(ShipAPI ship) {
162                FindShipFilter filter = new FindShipFilter() {
163                        public boolean matches(ShipAPI ship) {
164                                return !ship.getEngineController().isFlamedOut();
165                        }
166                };
167                
168                float range = getMaxRange(ship);
169                boolean player = ship == Global.getCombatEngine().getPlayerShip();
170                ShipAPI target = ship.getShipTarget();
171                if (target != null) {
172                        float dist = Misc.getDistance(ship.getLocation(), target.getLocation());
173                        float radSum = ship.getCollisionRadius() + target.getCollisionRadius();
174                        if (dist > range + radSum) target = null;
175                } else {
176                        if (target == null || target.getOwner() == ship.getOwner()) {
177                                if (player) {
178                                        target = Misc.findClosestShipEnemyOf(ship, ship.getMouseTarget(), HullSize.FIGHTER, range, true, filter);
179                                } else {
180                                        Object test = ship.getAIFlags().getCustom(AIFlags.MANEUVER_TARGET);
181                                        if (test instanceof ShipAPI) {
182                                                target = (ShipAPI) test;
183                                                float dist = Misc.getDistance(ship.getLocation(), target.getLocation());
184                                                float radSum = ship.getCollisionRadius() + target.getCollisionRadius();
185                                                if (dist > range + radSum) target = null;
186                                        }
187                                }
188                        }
189                        if (target == null) {
190                                target = Misc.findClosestShipEnemyOf(ship, ship.getLocation(), HullSize.FIGHTER, range, true, filter);
191                        }
192                }
193                
194                return target;
195        }
196        
197        
198        protected float getMaxRange(ShipAPI ship) {
199                return RANGE;
200        }
201
202        
203        public StatusData getStatusData(int index, State state, float effectLevel) {
204//              if (effectLevel > 0) {
205//                      if (index == 0) {
206//                              float damMult = 1f + (DAM_MULT - 1f) * effectLevel;
207//                              return new StatusData("" + (int)((damMult - 1f) * 100f) + "% more damage to target", false);
208//                      }
209//              }
210                return null;
211        }
212
213
214        @Override
215        public String getInfoText(ShipSystemAPI system, ShipAPI ship) {
216                if (system.isOutOfAmmo()) return null;
217                if (system.getState() != SystemState.IDLE) return null;
218                
219                ShipAPI target = findTarget(ship);
220                if (target != null && target != ship) {
221                        return "READY";
222                }
223                if (target == null && ship.getShipTarget() != null) {
224                        return "OUT OF RANGE";
225                }
226                return "NO TARGET";
227        }
228
229        
230        @Override
231        public boolean isUsable(ShipSystemAPI system, ShipAPI ship) {
232                if (system.isActive()) return true;
233                ShipAPI target = findTarget(ship);
234                return target != null && target != ship;
235        }
236
237}
238
239
240
241
242
243
244
245