001package com.fs.starfarer.api.impl.campaign.skills;
002
003import java.util.HashSet;
004import java.util.List;
005import java.util.Set;
006
007import com.fs.starfarer.api.Global;
008import com.fs.starfarer.api.characters.PersonAPI;
009import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
010import com.fs.starfarer.api.combat.BattleObjectiveAPI;
011import com.fs.starfarer.api.combat.CombatEngineAPI;
012import com.fs.starfarer.api.combat.CombatFleetManagerAPI;
013import com.fs.starfarer.api.combat.DeployedFleetMemberAPI;
014import com.fs.starfarer.api.combat.ShipAPI;
015import com.fs.starfarer.api.combat.ViewportAPI;
016import com.fs.starfarer.api.impl.campaign.ids.BattleObjectives;
017import com.fs.starfarer.api.impl.campaign.ids.Stats;
018import com.fs.starfarer.api.input.InputEventAPI;
019
020public class ElectronicWarfareScript extends BaseEveryFrameCombatPlugin {
021        public static Object KEY_STATUS = new Object();
022        public static Object KEY_STATUS_ENEMY_RATING = new Object();
023        public static Object KEY_STATUS2 = new Object();
024        
025        public static float BASE_MAXIMUM = 10;
026        
027        public static float PER_JAMMER = 5;
028        
029        public static String PENALTY_ID = "electronic_warfare_penalty";
030        
031        private CombatEngineAPI engine;
032        public void init(CombatEngineAPI engine) {
033                this.engine = engine;
034        }
035        
036        
037//      public ElectronicWarfareScript() {
038//              System.out.println("WEFWEGWGWEGF124");
039//      }
040        
041        private ShipAPI prevPlayerShip = null;
042        private int skipFrames = 0;
043        private Set<CombatFleetManagerAPI> needsCleanup = new HashSet<CombatFleetManagerAPI>();
044        public void advance(float amount, List<InputEventAPI> events) {
045                if (engine == null) return;
046                if (engine.isPaused()) return;
047                
048                
049                // if the player changed flagships:
050                // skip a few frames to make sure the status ends up on top of the status list
051                ShipAPI playerShip = engine.getPlayerShip();
052                if (playerShip != prevPlayerShip) {
053                        prevPlayerShip = playerShip;
054                        skipFrames = 20;
055                }
056                
057                if (skipFrames > 0) {
058                        skipFrames--;
059                        return;
060                }
061                
062                
063                int [] player = getTotalAndMaximum(engine.getFleetManager(0));
064                int [] enemy = getTotalAndMaximum(engine.getFleetManager(1));
065                
066                
067                if (player == null || enemy == null) {
068                        cleanUpIfNeeded(engine.getFleetManager(0));
069                        cleanUpIfNeeded(engine.getFleetManager(1));
070                        return;
071                }
072                
073                if (engine.getFleetManager(0) == null || engine.getFleetManager(1) == null) {
074                        cleanUpIfNeeded(engine.getFleetManager(0));
075                        cleanUpIfNeeded(engine.getFleetManager(1));
076                        return;
077                }
078                
079                //player[0] = 20;
080                
081                float pTotal = player[0];
082                float pMax = player[1];
083                
084                float eTotal = enemy[0];
085                float eMax = enemy[1];
086
087//              float origEMax = eMax;
088//              if (player[2] > 0) {
089//                      float pExcess = pTotal - pMax * 2f;
090//                      if (pExcess > 0) {
091//                              eMax -= pExcess * 0.5f;
092//                              if (eMax < 0) eMax = 0;
093//                      }
094//              }
095//              
096//              if (enemy[2] > 0) {
097//                      float eExcess = eTotal - origEMax * 2f;
098//                      if (eExcess > 0) {
099//                              pMax -= eExcess * 0.5f;
100//                              if (pMax < 0) pMax = 0;
101//                      }
102//              }
103                
104                if (pTotal <= 0) cleanUpIfNeeded(engine.getFleetManager(1));
105                if (eTotal <= 0) cleanUpIfNeeded(engine.getFleetManager(0));
106
107                
108                int totalPenalty = (int) Math.round(Math.min(BASE_MAXIMUM, pTotal + eTotal));
109                if (totalPenalty <= 0f) return;
110
111                float ecmRatingToPenaltyMult = 1f;
112                
113                float playerPenalty = (int) Math.min(eTotal * ecmRatingToPenaltyMult, eMax);
114                if (pTotal > 0 && playerPenalty > 0) {
115                        float pMult = eTotal / (eTotal + pTotal);
116                        playerPenalty *= pMult;
117                }
118                
119                float enemyPenalty = (int) Math.min(pTotal * ecmRatingToPenaltyMult, pMax);
120                if (eTotal > 0 && enemyPenalty > 0) {
121                        float eMult = pTotal / (eTotal + pTotal);
122                        enemyPenalty *= eMult;
123                }
124                
125                playerPenalty = Math.round(playerPenalty);
126                enemyPenalty = Math.round(enemyPenalty);
127                
128
129                String icon = Global.getSettings().getSpriteName("ui", "icon_tactical_electronic_warfare");
130                
131                if (playerPenalty > 0 || eTotal > 0) {
132                        applyPenalty(engine.getFleetManager(0), playerPenalty, eMax);
133                        
134                        String sMax = "";
135                        if (eMax <= playerPenalty) sMax = " (max)";
136                        String title = "Enemy ECM rating:" + " " + (int) eTotal + "%";
137                        String data = "-" + (int)playerPenalty + "% weapon range" + sMax;
138                        if (eMax <= 0) {
139                                data = "fully neutralized";
140                        }
141                        engine.maintainStatusForPlayerShip(KEY_STATUS_ENEMY_RATING, icon, title, data, eMax > 0);
142                }
143                
144                if (enemyPenalty > 0 || pTotal > 0) {
145                        applyPenalty(engine.getFleetManager(1), enemyPenalty, pMax);
146                        
147                        String sMax = "";
148                        if (pMax <= enemyPenalty) sMax = " (max)";
149                        String title = "ECM rating:" + " " + (int) pTotal + "%";
150                        String data = "-" + (int)enemyPenalty + "% enemy weapon range" + sMax;
151                        if (pMax <= 0) {
152                                data = "fully neutralized";
153                        }
154                        engine.maintainStatusForPlayerShip(KEY_STATUS, icon, title, data, false);                       
155                }
156                
157                if (playerPenalty > 0 && eMax > 0 && engine.getPlayerShip() != null) {
158                        int eccm = 100 - (int) Math.round(engine.getPlayerShip().getMutableStats().getDynamic().getValue(Stats.ELECTRONIC_WARFARE_PENALTY_MOD, 100f));
159                        if (eccm > 100) eccm = 100;
160                        if (eccm < 0) eccm = 0;
161                        //eccm = -eccm;
162                        if (eccm != 0) {
163                                //engine.maintainStatusForPlayerShip(KEY_STATUS2, icon, "On-board ECCM", "up to " + eccm + "% ecm neutralized", false);
164                                engine.maintainStatusForPlayerShip(KEY_STATUS2, icon, "On-board ECCM", "" + eccm + "% enemy ecm neutralized", false);
165                        }
166                }
167                
168/*              
169                //KEY_STATUS_ENEMY_RATING
170                float diff = pTotal - eTotal;
171                
172                if (diff == 0) {
173                        cleanUpIfNeeded(engine.getFleetManager(0));
174                        cleanUpIfNeeded(engine.getFleetManager(1));
175                        return;
176                }
177                
178                
179                CombatFleetManagerAPI winner = engine.getFleetManager(0);
180                CombatFleetManagerAPI loser = engine.getFleetManager(1);
181                
182                float max = pMax;
183                if (diff < 0) {
184                        CombatFleetManagerAPI temp = winner;
185                        winner = loser;
186                        loser = temp;
187                        max = eMax;
188                }
189                
190                float penalty = Math.min(Math.abs(diff), max);
191                
192                cleanUpIfNeeded(winner);
193                applyPenalty(loser, penalty, max);
194                
195                
196                boolean playerWon = winner.getOwner() == engine.getPlayerShip().getOwner(); 
197                                        
198                String title = "ECM rating:" + " " + (int) pTotal + "% vs " + (int)eTotal + "%";
199                String data = "-" + (int)penalty + "% weapon range";
200                if (playerWon) {
201                        data = "-" + (int)penalty + "% enemy weapon range";
202                }
203                
204                String icon = Global.getSettings().getSpriteName("ui", "icon_tactical_electronic_warfare");
205                
206                if (engine.getPlayerShip() != null && !playerWon) {
207                        int eccm = 100 - (int) Math.round(engine.getPlayerShip().getMutableStats().getDynamic().getValue(Stats.ELECTRONIC_WARFARE_PENALTY_MOD, 100f));
208                        if (eccm > 100) eccm = 100;
209                        if (eccm < 0) eccm = 0;
210                        //eccm = -eccm;
211                        if (eccm != 0) {
212                                //engine.maintainStatusForPlayerShip(KEY_STATUS2, icon, "On-board ECCM", "up to " + eccm + "% ecm neutralized", false);
213                                engine.maintainStatusForPlayerShip(KEY_STATUS2, icon, "On-board ECCM", "" + eccm + "% ecm neutralized", false);
214                        }
215                }
216                
217                engine.maintainStatusForPlayerShip(KEY_STATUS, icon, title, data, !playerWon);
218                */
219        }
220        
221        private void applyPenalty(CombatFleetManagerAPI manager, float penalty, float maxPenalty) {
222                List<DeployedFleetMemberAPI> deployed = manager.getDeployedCopyDFM();
223                for (DeployedFleetMemberAPI member : deployed) {
224                        if (member.isFighterWing()) continue;
225                        if (member.getShip() == null) continue;
226                        
227                        float currPenalty = penalty * member.getShip().getMutableStats().getDynamic().getValue(Stats.ELECTRONIC_WARFARE_PENALTY_MULT);
228                        currPenalty = member.getShip().getMutableStats().getDynamic().getValue(Stats.ELECTRONIC_WARFARE_PENALTY_MOD, currPenalty);
229                        if (currPenalty < 0) currPenalty = 0;
230                        
231                        float maxMod = penalty * member.getShip().getMutableStats().getDynamic().getValue(Stats.ELECTRONIC_WARFARE_PENALTY_MAX_FOR_SHIP_MOD, 0);
232                        float currMax = maxPenalty + maxMod;
233                        if (currPenalty > currMax) {
234                                currPenalty = currMax;
235                        }
236                        
237                        member.getShip().getMutableStats().getBallisticWeaponRangeBonus().modifyMult(PENALTY_ID, 1f - currPenalty/100f);
238                        member.getShip().getMutableStats().getEnergyWeaponRangeBonus().modifyMult(PENALTY_ID, 1f - currPenalty/100f);
239                        member.getShip().getMutableStats().getMissileWeaponRangeBonus().modifyMult(PENALTY_ID, 1f - currPenalty/100f);
240                }
241                
242                needsCleanup.add(manager);
243        }
244        
245        protected void cleanUpIfNeeded(CombatFleetManagerAPI manager) {
246                if (needsCleanup.contains(manager)) {
247                        needsCleanup.remove(manager);
248                        List<DeployedFleetMemberAPI> deployed = manager.getDeployedCopyDFM();
249                        for (DeployedFleetMemberAPI member : deployed) {
250                                if (member.isFighterWing()) continue;
251                                if (member.getShip() == null) continue;
252                                
253                                member.getShip().getMutableStats().getBallisticWeaponRangeBonus().unmodify(PENALTY_ID);
254                                member.getShip().getMutableStats().getEnergyWeaponRangeBonus().unmodify(PENALTY_ID);
255                                member.getShip().getMutableStats().getMissileWeaponRangeBonus().unmodify(PENALTY_ID);
256                        }
257                }
258        }
259        
260        private int [] getTotalAndMaximum(CombatFleetManagerAPI manager) {
261//              PersonAPI commander = manager.getFleetCommander();
262//              if (commander == null) {
263//                      return null;
264//              }
265//              float max = BASE_MAXIMUM + commander.getStats().getDynamic().getValue(Stats.ELECTRONIC_WARFARE_MAX, 0f);
266                
267                float max = 0f;
268                for (PersonAPI commander : manager.getAllFleetCommanders()) {
269                        max = Math.max(max, BASE_MAXIMUM + commander.getStats().getDynamic().getValue(Stats.ELECTRONIC_WARFARE_MAX, 0f));
270                }
271                
272                
273                float total = 0f;
274                List<DeployedFleetMemberAPI> deployed = manager.getDeployedCopyDFM();
275                float canCounter = 0f;
276                for (DeployedFleetMemberAPI member : deployed) {
277                        if (member.isFighterWing()) continue;
278                        if (member.isStationModule()) continue;
279                        float curr = member.getShip().getMutableStats().getDynamic().getValue(Stats.ELECTRONIC_WARFARE_FLAT, 0f);
280                        total += curr;
281                        
282                        canCounter += member.getShip().getMutableStats().getDynamic().getValue(Stats.SHIP_BELONGS_TO_FLEET_THAT_CAN_COUNTER_EW, 0f);
283                }
284                
285                for (BattleObjectiveAPI obj : engine.getObjectives()) {
286                        if (obj.getOwner() == manager.getOwner() && BattleObjectives.SENSOR_JAMMER.equals(obj.getType())) {
287                                total += PER_JAMMER;
288                        }
289                }
290
291                int counter = 0;
292                if (canCounter > 0) counter = 1;
293
294                return new int [] {(int) total, (int) max, counter};
295        }
296
297        
298        
299        
300        
301        public void renderInUICoords(ViewportAPI viewport) {
302        }
303
304        public void renderInWorldCoords(ViewportAPI viewport) {
305        }
306
307}