Starsector API
Loading...
Searching...
No Matches
InterdictorArrayStats.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.combat;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.Collections;
6import java.util.List;
7
8import com.fs.starfarer.api.Global;
9import com.fs.starfarer.api.combat.CombatEngineAPI;
10import com.fs.starfarer.api.combat.MutableShipStatsAPI;
11import com.fs.starfarer.api.combat.ShipAPI;
12import com.fs.starfarer.api.combat.ShipEngineControllerAPI;
13import com.fs.starfarer.api.combat.ShipSystemAPI;
14import com.fs.starfarer.api.combat.ShipAPI.HullSize;
15import com.fs.starfarer.api.combat.ShipEngineControllerAPI.ShipEngineAPI;
16import com.fs.starfarer.api.combat.ShipSystemAPI.SystemState;
17import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags;
18import com.fs.starfarer.api.util.Misc;
19import com.fs.starfarer.api.util.Misc.FindShipFilter;
20
22 public static final Object SHIP_KEY = new Object();
23 public static final Object TARGET_KEY = new Object();
24
25 public static final float WING_EFFECT_RANGE = 200f;
26
27 public static final float RANGE = 1000f;
28 public static final Color EFFECT_COLOR = new Color(100,165,255,75);
29
30
31 public static class TargetData {
32 public ShipAPI target;
33 public float sinceLastAfterimage = 0f;
34 public boolean lastAbove = false;
35 public TargetData(ShipAPI target) {
36 this.target = target;
37 }
38 }
39
40 public void apply(MutableShipStatsAPI stats, final String id, State state, float effectLevel) {
41 ShipAPI ship = null;
42 if (stats.getEntity() instanceof ShipAPI) {
43 ship = (ShipAPI) stats.getEntity();
44 } else {
45 return;
46 }
47
48 final String targetDataKey = ship.getId() + "_interdictor_target_data";
49
50 Object targetDataObj = Global.getCombatEngine().getCustomData().get(targetDataKey);
51 if (state == State.IN && targetDataObj == null) {
52 ShipAPI target = findTarget(ship);
53 Global.getCombatEngine().getCustomData().put(targetDataKey, new TargetData(target));
54 } else if (state == State.IDLE && targetDataObj != null) {
55 Global.getCombatEngine().getCustomData().remove(targetDataKey);
56 }
57 if (targetDataObj == null || ((TargetData) targetDataObj).target == null) return;
58
59 final TargetData targetData = (TargetData) targetDataObj;
60
61 //ShipAPI target = targetData.target;
62 List<ShipAPI> targets = new ArrayList<ShipAPI>();
63 if (targetData.target.isFighter() || targetData.target.isDrone()) {
64 CombatEngineAPI engine = Global.getCombatEngine();
65 List<ShipAPI> ships = engine.getShips();
66 for (ShipAPI other : ships) {
67 if (other.isShuttlePod()) continue;
68 if (other.isHulk()) continue;
69 if (!other.isDrone() && !other.isFighter()) continue;
70 if (other.getOriginalOwner() != targetData.target.getOriginalOwner()) continue;
71
72 float dist = Misc.getDistance(other.getLocation(), targetData.target.getLocation());
73 if (dist > WING_EFFECT_RANGE) continue;
74
75 targets.add(other);
76 }
77 } else {
78 targets.add(targetData.target);
79 }
80
81 boolean first = true;
82 for (ShipAPI target : targets) {
83 if (effectLevel >= 1) {
84 Color color = getEffectColor(target);
85 color = Misc.setAlpha(color, 255);
86
87 if (first) {
88 if (target.getFluxTracker().showFloaty() ||
89 ship == Global.getCombatEngine().getPlayerShip() ||
90 target == Global.getCombatEngine().getPlayerShip()) {
91 target.getFluxTracker().showOverloadFloatyIfNeeded("Drive Interdicted!", color, 4f, true);
92 }
93 first = false;
94 }
95
96 ShipEngineControllerAPI ec = target.getEngineController();
97 float limit = ec.getFlameoutFraction();
98 if (target.isDrone() || target.isFighter()) {
99 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
static CombatEngineAPI getCombatEngine()
Definition Global.java:63
void apply(MutableShipStatsAPI stats, final String id, State state, float effectLevel)
String getInfoText(ShipSystemAPI system, ShipAPI ship)
boolean isUsable(ShipSystemAPI system, ShipAPI ship)
StatusData getStatusData(int index, State state, float effectLevel)