Starsector API
Loading...
Searching...
No Matches
LidarArrayStats.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.combat;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.Comparator;
6import java.util.List;
7
8import java.awt.Color;
9
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.combat.MutableShipStatsAPI;
12import com.fs.starfarer.api.combat.ShipAPI;
13import com.fs.starfarer.api.combat.WeaponAPI;
14import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
15import com.fs.starfarer.api.impl.campaign.ids.Tags;
16import com.fs.starfarer.api.util.Misc;
17
19
20 public static String LIDAR_WINDUP = "lidar_windup";
21
22 public static Color WEAPON_GLOW = new Color(255,50,50,155);
23
24 public static float RANGE_BONUS = 100f;
25 public static float PASSIVE_RANGE_BONUS = 35f;
26 public static float ROF_BONUS = 2f;
27 public static float RECOIL_BONUS = 75f;
28 public static float PROJECTILE_SPEED_BONUS = 50f;
29
30
31 public static class LidarDishData {
32 public float turnDir;
33 public float turnRate;
34 public float angle;
35 public float phase;
36 public float count;
37 public WeaponAPI w;
38 }
39
40 protected List<LidarDishData> dishData = new ArrayList<LidarArrayStats.LidarDishData>();
41 protected boolean needsUnapply = false;
42 protected boolean playedWindup = false;
43
44 protected boolean inited = false;
45 public void init(ShipAPI ship) {
46 if (inited) return;
47 inited = true;
48
49 needsUnapply = true;
50
51 int turnDir = 1;
52 float index = 0f;
53 float count = 0f;
54 for (WeaponAPI w : ship.getAllWeapons()) {
55 if (w.isDecorative() && w.getSpec().hasTag(Tags.LIDAR)) {
56 count++;
57 }
58 }
59 List<WeaponAPI> lidar = new ArrayList<WeaponAPI>();
60 for (WeaponAPI w : ship.getAllWeapons()) {
61 if (w.isDecorative() && w.getSpec().hasTag(Tags.LIDAR)) {
62 lidar.add(w);
63 }
64 }
65 Collections.sort(lidar, new Comparator<WeaponAPI>() {
66 public int compare(WeaponAPI o1, WeaponAPI o2) {
67 return (int) Math.signum(o1.getSlot().getLocation().x - o2.getSlot().getLocation().x);
68 }
69 });
70 for (WeaponAPI w : lidar) {
71 if (w.isDecorative() && w.getSpec().hasTag(Tags.LIDAR)) {
72 w.setSuspendAutomaticTurning(true);
73 LidarDishData data = new LidarDishData();
74 data.turnDir = Math.signum(turnDir);
75 data.turnRate = 0.5f;
76 data.turnRate = 0.1f;
77 data.w = w;
78 data.angle = 0f;
79 data.phase = index / count;
80 data.count = count;
81 dishData.add(data);
82 turnDir = -turnDir;
83 index++;
84 }
85 }
86 }
87
88 public void rotateLidarDishes(boolean active, float effectLevel) {
90
91 float turnRateMult = 1f;
92 if (active) {
93 turnRateMult = 20f;
94 }
95 //turnRateMult = 0.1f;
96 //boolean first = true;
97 for (LidarDishData data : dishData) {
98 float arc = data.w.getArc();
99 float useTurnDir = data.turnDir;
100 if (active) {
101 useTurnDir = Misc.getClosestTurnDirection(data.angle, 0f);
102 }
103 float delta = useTurnDir * amount * data.turnRate * turnRateMult * arc;
104 if (active && effectLevel > 0f && Math.abs(data.angle) < Math.abs(delta * 1.5f)) {
105 data.angle = 0f;
106 } else {
107 data.angle += delta;
108 data.phase += 1f * amount;
109 if (arc < 360f) {
110 if (data.angle > arc/2f && data.turnDir > 0f) {
111 data.angle = arc/2f;
112 data.turnDir = -1f;
113 }
114 if (data.angle < -arc/2f && data.turnDir < 0f) {
115 data.angle = -arc/2f;
116 data.turnDir = 1f;
117 }
118 } else {
119 data.angle = data.angle % 360f;
120 }
121 }
122
123
124 float facing = data.angle + data.w.getArcFacing() + data.w.getShip().getFacing();
125 data.w.setFacing(facing);
126 data.w.updateBeamFromPoints();
127// if (first) {
128// System.out.println("Facing: " + facing);
129// first = false;
130// }
131 }
132 }
133
134 public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
135 ShipAPI ship = (ShipAPI)stats.getEntity();
136 if (ship == null || ship.isHulk()) {
137 if (needsUnapply) {
138 unmodify(id, stats);
139 for (WeaponAPI w : ship.getAllWeapons()) {
140 if (!w.isDecorative() && w.getSlot().isHardpoint() && !w.isBeam() &&
141 (w.getType() == WeaponType.BALLISTIC || w.getType() == WeaponType.ENERGY)) {
142 w.setGlowAmount(0, null);
143 }
144 }
145 needsUnapply = false;
146 }
147 return;
148 }
149
150 init(ship);
151
152 //lidarFacingOffset += am
153
154 boolean active = state == State.IN || state == State.ACTIVE || state == State.OUT;
155
156 rotateLidarDishes(active, effectLevel);
157
158 if (active) {
159 modify(id, stats, effectLevel);
160 needsUnapply = true;
161 } else {
162 if (needsUnapply) {
163 unmodify(id, stats);
164 for (WeaponAPI w : ship.getAllWeapons()) {
165 if (w.getSlot().isSystemSlot()) continue;
166 if (!w.isDecorative() && w.getSlot().isHardpoint() && !w.isBeam() &&
167 (w.getType() == WeaponType.BALLISTIC || w.getType() == WeaponType.ENERGY)) {
168 w.setGlowAmount(0, null);
169 }
170 }
171 needsUnapply = false;
172 }
173 }
174
175 if (!active) return;
176
177
178 for (WeaponAPI w : ship.getAllWeapons()) {
179 if (w.getSlot().isSystemSlot()) continue;
180 if (w.getType() == WeaponType.MISSILE) continue;
181 if (state == State.IN) {
182 if (!(w.isDecorative() && w.getSpec().hasTag(Tags.LIDAR))) {
183 w.setForceNoFireOneFrame(true);
184 }
185 } else {
186 if (!(!w.isDecorative() && w.getSlot().isHardpoint() && !w.isBeam() &&
187 (w.getType() == WeaponType.BALLISTIC || w.getType() == WeaponType.ENERGY))) {
188 w.setForceNoFireOneFrame(true);
189 }
190 }
191 }
192
193 Color glowColor = WEAPON_GLOW;
194
195 float lidarRange = 500;
196 for (WeaponAPI w : ship.getAllWeapons()) {
197 if (!w.isDecorative() && w.getSlot().isHardpoint() && !w.isBeam() &&
198 (w.getType() == WeaponType.BALLISTIC || w.getType() == WeaponType.ENERGY)) {
199 lidarRange = Math.max(lidarRange, w.getRange());
200 w.setGlowAmount(effectLevel, glowColor);
201 }
202 }
203 lidarRange += 100f;
204 stats.getBeamWeaponRangeBonus().modifyFlat("lidararray", lidarRange);
205// for (WeaponAPI w : ship.getAllWeapons()) {
206// if (w.isDecorative() && w.getSpec().hasTag(Tags.LIDAR)) {
207// if (state == State.IN) {
208// w.setForceFireOneFrame(true);
209// }
210// }
211// }
212
213 // always wait a quarter of a second before starting to fire the targeting lasers
214 // this is the worst-case turn time required for the dishes to face front
215 // doing this to keep the timing of the lidar ping sounds consistent relative
216 // to when the windup sound plays
217 float fireThreshold = 0.25f / 3.25f;
218 fireThreshold += 0.02f; // making sure there's only 4 lidar pings; lines up with the timing of the lidardish weapon
219 //fireThreshold = 0f;
220 for (LidarDishData data : dishData) {
221 boolean skip = data.phase % 1f > 1f / data.count;
222 //skip = data.phase % 1f > 0.67f;
223 skip = false;
224 if (skip) continue;
225 if (data.w.isDecorative() && data.w.getSpec().hasTag(Tags.LIDAR)) {
226 if (state == State.IN && Math.abs(data.angle) < 5f && effectLevel >= fireThreshold) {
227 data.w.setForceFireOneFrame(true);
228 }
229 }
230 }
231
232 if (((state == State.IN && effectLevel > 0.67f) || state == State.ACTIVE) && !playedWindup) {
234 playedWindup = true;
235 }
236 }
237
238
239 protected void modify(String id, MutableShipStatsAPI stats, float effectLevel) {
240 float mult = 1f + ROF_BONUS * effectLevel;
241 //float mult = 1f + ROF_BONUS;
244 stats.getBallisticRoFMult().modifyMult(id, mult);
245 stats.getEnergyRoFMult().modifyMult(id, mult);
246 //stats.getBallisticWeaponFluxCostMod().modifyMult(id, 1f - (FLUX_REDUCTION * 0.01f));
247 stats.getMaxRecoilMult().modifyMult(id, 1f - (0.01f * RECOIL_BONUS));
248 stats.getRecoilPerShotMult().modifyMult(id, 1f - (0.01f * RECOIL_BONUS));
249 stats.getRecoilDecayMult().modifyMult(id, 1f - (0.01f * RECOIL_BONUS));
250
253 }
254 protected void unmodify(String id, MutableShipStatsAPI stats) {
257// stats.getBallisticWeaponRangeBonus().unmodifyPercent(id);
258// stats.getEnergyWeaponRangeBonus().unmodifyPercent(id);
259
261 stats.getEnergyRoFMult().unmodifyMult(id);
262 stats.getMaxRecoilMult().unmodifyMult(id);
265
268
269 playedWindup = false;
270 }
271
272
273 public void unapply(MutableShipStatsAPI stats, String id) {
274 // never called due to runScriptWhileIdle:true in the .system file
275 }
276
277 public StatusData getStatusData(int index, State state, float effectLevel) {
278 if (state == State.IDLE || state == State.COOLDOWN) {
279 if (index == 3) {
280 return new StatusData("weapon range +" + (int) PASSIVE_RANGE_BONUS + "%", false);
281 }
282 }
283 if (effectLevel <= 0f) return null;
284
285 //float mult = 1f + ROF_BONUS;
286 float mult = 1f + ROF_BONUS;
287 float bonusPercent = (int) ((mult - 1f) * 100f);
288 if (index == 3) {
289 return new StatusData("weapon range +" + (int) RANGE_BONUS + "%", false);
290 }
291 if (index == 2) {
292 return new StatusData("rate of fire +" + (int) bonusPercent + "%", false);
293 }
294// if (index == 1) {
295// return new StatusData("ballistic flux use -" + (int) FLUX_REDUCTION + "%", false);
296// }
297 if (index == 1) {
298 return new StatusData("weapon recoil -" + (int) RECOIL_BONUS + "%", false);
299 }
300 if (index == 0 && PROJECTILE_SPEED_BONUS > 0) {
301 return new StatusData("projectile speed +" + (int) PROJECTILE_SPEED_BONUS + "%", false);
302 }
303 return null;
304 }
305
306 public String getDisplayNameOverride(State state, float effectLevel) {
307 if (state == State.IDLE || state == State.COOLDOWN) {
308 return "lidar array - passive";
309 }
310 return null;
311 }
312
313}
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:49
static CombatEngineAPI getCombatEngine()
Definition Global.java:69
void modifyPercent(String source, float value)
void modifyMult(String source, float value)
void modifyPercent(String source, float value)
void modifyFlat(String source, float value)
void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel)
void unmodify(String id, MutableShipStatsAPI stats)
void rotateLidarDishes(boolean active, float effectLevel)
void unapply(MutableShipStatsAPI stats, String id)
void modify(String id, MutableShipStatsAPI stats, float effectLevel)
String getDisplayNameOverride(State state, float effectLevel)
StatusData getStatusData(int index, State state, float effectLevel)
static float getClosestTurnDirection(float facing, float desired)
Definition Misc.java:2102
SoundAPI playSound(String id, float pitch, float volume, Vector2f loc, Vector2f vel)
List< WeaponAPI > getAllWeapons()