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}