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