001package com.fs.starfarer.api.impl.combat;
002
003import java.util.List;
004
005import java.awt.Color;
006
007import com.fs.starfarer.api.Global;
008import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
009import com.fs.starfarer.api.combat.MutableShipStatsAPI;
010import com.fs.starfarer.api.combat.ShipAPI;
011import com.fs.starfarer.api.combat.ShipAPI.HullSize;
012import com.fs.starfarer.api.combat.ShipSystemAPI;
013import com.fs.starfarer.api.combat.ShipSystemAPI.SystemState;
014import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags;
015import com.fs.starfarer.api.combat.WeaponAPI;
016import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
017import com.fs.starfarer.api.input.InputEventAPI;
018import com.fs.starfarer.api.util.Misc;
019
020public class AcausalDisruptorStats extends BaseShipSystemScript {
021        //public static final float ENERGY_DAM_PENALTY_MULT = 0.5f;
022        public static float ENERGY_DAM_PENALTY_MULT = 1f;
023        
024        public static float DISRUPTION_DUR = 1f;
025        protected static float MIN_DISRUPTION_RANGE = 500f;
026        
027        public static final Color OVERLOAD_COLOR = new Color(255,155,255,255);
028        
029        public static final Color JITTER_COLOR = new Color(255,155,255,75);
030        public static final Color JITTER_UNDER_COLOR = new Color(255,155,255,155);
031
032        
033        public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
034                ShipAPI ship = null;
035                //boolean player = false;
036                if (stats.getEntity() instanceof ShipAPI) {
037                        ship = (ShipAPI) stats.getEntity();
038                        //player = ship == Global.getCombatEngine().getPlayerShip();
039                } else {
040                        return;
041                }
042                
043                //stats.getEnergyWeaponDamageMult().modifyMult(id, 1f - (1f - ENERGY_DAM_PENALTY_MULT) * effectLevel);
044                stats.getEnergyWeaponDamageMult().modifyMult(id, ENERGY_DAM_PENALTY_MULT);
045                
046                float jitterLevel = effectLevel;
047                if (state == State.OUT) {
048                        jitterLevel *= jitterLevel;
049                }
050                float maxRangeBonus = 50f;
051                //float jitterRangeBonus = jitterLevel * maxRangeBonus;
052                float jitterRangeBonus = jitterLevel * maxRangeBonus;
053                if (state == State.OUT) {
054                        //jitterRangeBonus = maxRangeBonus + (1f - jitterLevel) * maxRangeBonus; 
055                }
056                
057                ship.setJitterUnder(this, JITTER_UNDER_COLOR, jitterLevel, 21, 0f, 3f + jitterRangeBonus);
058                //ship.setJitter(this, JITTER_COLOR, jitterLevel, 4, 0f, 0 + jitterRangeBonus * 0.67f);
059                ship.setJitter(this, JITTER_COLOR, jitterLevel, 4, 0f, 0 + jitterRangeBonus);
060                
061                String targetKey = ship.getId() + "_acausal_target";
062                Object foundTarget = Global.getCombatEngine().getCustomData().get(targetKey); 
063                if (state == State.IN) {
064                        if (foundTarget == null) {
065                                ShipAPI target = findTarget(ship);
066                                if (target != null) {
067                                        Global.getCombatEngine().getCustomData().put(targetKey, target);
068                                }
069                        }
070                } else if (effectLevel >= 1) {
071                        if (foundTarget instanceof ShipAPI) {
072                                ShipAPI target = (ShipAPI) foundTarget;
073                                if (target.getFluxTracker().isOverloadedOrVenting()) target = ship;
074                                applyEffectToTarget(ship, target);
075                        }
076                } else if (state == State.OUT && foundTarget != null) {
077                        Global.getCombatEngine().getCustomData().remove(targetKey);
078                }
079        }
080        
081        
082        public void unapply(MutableShipStatsAPI stats, String id) {
083                stats.getEnergyWeaponDamageMult().unmodify(id);
084        }
085        
086        protected ShipAPI findTarget(ShipAPI ship) {
087                float range = getMaxRange(ship);
088                boolean player = ship == Global.getCombatEngine().getPlayerShip();
089                ShipAPI target = ship.getShipTarget();
090                if (ship.getShipAI() != null && ship.getAIFlags().hasFlag(AIFlags.TARGET_FOR_SHIP_SYSTEM)){
091                        target = (ShipAPI) ship.getAIFlags().getCustom(AIFlags.TARGET_FOR_SHIP_SYSTEM);
092                }
093                
094                if (target != null) {
095                        float dist = Misc.getDistance(ship.getLocation(), target.getLocation());
096                        float radSum = ship.getCollisionRadius() + target.getCollisionRadius();
097                        if (dist > range + radSum) target = null;
098                } else {
099                        if (target == null || target.getOwner() == ship.getOwner()) {
100                                if (player) {
101                                        target = Misc.findClosestShipEnemyOf(ship, ship.getMouseTarget(), HullSize.FRIGATE, range, true);
102                                } else {
103                                        Object test = ship.getAIFlags().getCustom(AIFlags.MANEUVER_TARGET);
104                                        if (test instanceof ShipAPI) {
105                                                target = (ShipAPI) test;
106                                                float dist = Misc.getDistance(ship.getLocation(), target.getLocation());
107                                                float radSum = ship.getCollisionRadius() + target.getCollisionRadius();
108                                                if (dist > range + radSum || target.isFighter()) target = null;
109                                        }
110                                }
111                        }
112                }
113                
114                if (target != null && target.isFighter()) target = null;
115                if (target == null) {
116                        target = Misc.findClosestShipEnemyOf(ship, ship.getLocation(), HullSize.FRIGATE, range, true);
117                }
118                if (target == null || target.getFluxTracker().isOverloadedOrVenting()) target = ship;
119                
120                return target;
121        }
122        
123        
124        public static float getMaxRange(ShipAPI ship) {
125                if (true) {
126                        return ship.getMutableStats().getSystemRangeBonus().computeEffective(MIN_DISRUPTION_RANGE);
127                        //return MIN_DISRUPTION_RANGE;
128                }
129                
130                float range = 0f;
131                
132                for (WeaponAPI w : ship.getAllWeapons()) {
133                        if (w.getType() == WeaponType.BALLISTIC || w.getType() == WeaponType.ENERGY) {
134                                float curr = w.getRange();
135                                if (curr > range) range = curr;
136                        }
137                }
138                
139                return range + MIN_DISRUPTION_RANGE;
140        }
141
142        
143        protected void applyEffectToTarget(final ShipAPI ship, final ShipAPI target) {
144                if (target.getFluxTracker().isOverloadedOrVenting()) {
145                        return;
146                }
147                if (target == ship) return;
148                
149                target.setOverloadColor(OVERLOAD_COLOR);
150                target.getFluxTracker().beginOverloadWithTotalBaseDuration(DISRUPTION_DUR);
151                //target.getEngineController().forceFlameout(true);
152                
153                if (target.getFluxTracker().showFloaty() || 
154                                ship == Global.getCombatEngine().getPlayerShip() ||
155                                target == Global.getCombatEngine().getPlayerShip()) {
156                        target.getFluxTracker().playOverloadSound();
157                        target.getFluxTracker().showOverloadFloatyIfNeeded("System Disruption!", OVERLOAD_COLOR, 4f, true);
158                }
159                
160                Global.getCombatEngine().addPlugin(new BaseEveryFrameCombatPlugin() {
161                        @Override
162                        public void advance(float amount, List<InputEventAPI> events) {
163                                if (!target.getFluxTracker().isOverloadedOrVenting()) {
164                                        target.resetOverloadColor();
165                                        Global.getCombatEngine().removePlugin(this);
166                                }
167                        }
168                });
169        }
170        
171        public StatusData getStatusData(int index, State state, float effectLevel) {
172                //float percent = (1f - ENERGY_DAM_PENALTY_MULT) * effectLevel * 100;
173                float percent = (1f - ENERGY_DAM_PENALTY_MULT) * 100;
174                if (index == 0 && percent > 0) {
175                        return new StatusData((int)percent + "% less energy damage", false);
176                }
177                return null;
178        }
179
180
181        @Override
182        public String getInfoText(ShipSystemAPI system, ShipAPI ship) {
183                if (system.isOutOfAmmo()) return null;
184                if (system.getState() != SystemState.IDLE) return null;
185                
186                ShipAPI target = findTarget(ship);
187                if (target != null && target != ship) {
188                        return "READY";
189                }
190                if ((target == null || target == ship) && ship.getShipTarget() != null) {
191                        return "OUT OF RANGE";
192                }
193                return "NO TARGET";
194                //return super.getInfoText(system, ship);
195        }
196
197        
198        @Override
199        public boolean isUsable(ShipSystemAPI system, ShipAPI ship) {
200                ShipAPI target = findTarget(ship);
201                return target != null && target != ship;
202                //return super.isUsable(system, ship);
203        }
204        
205
206        
207}
208
209
210
211
212
213
214
215