Starsector API
Loading...
Searching...
No Matches
ThreatShipReclamationScript.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.combat.threat;
2
3import java.util.ArrayList;
4import java.util.List;
5
6import java.awt.Color;
7
8import org.lwjgl.util.vector.Vector2f;
9
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
12import com.fs.starfarer.api.combat.BoundsAPI.SegmentAPI;
13import com.fs.starfarer.api.combat.CombatEngineAPI;
14import com.fs.starfarer.api.combat.CombatFleetManagerAPI;
15import com.fs.starfarer.api.combat.ShipAPI;
16import com.fs.starfarer.api.impl.combat.RiftLanceEffect;
17import com.fs.starfarer.api.impl.combat.threat.ConstructionSwarmSystemScript.SwarmConstructableVariant;
18import com.fs.starfarer.api.impl.combat.threat.RoilingSwarmEffect.SwarmMember;
19import com.fs.starfarer.api.input.InputEventAPI;
20import com.fs.starfarer.api.util.IntervalUtil;
21import com.fs.starfarer.api.util.Misc;
22import com.fs.starfarer.api.util.WeightedRandomPicker;
23
25
26 public static float CR_PER_RECLAMATION_SWARM = 0.02f;
27
28 public static float RECLAMATION_SWARM_SPEED_MULT = 0.67f;
29 public static float RECLAMATION_SWARM_COLLISION_MULT = 1.5f;
30 public static float RECLAMATION_SWARM_RADIUS_MULT = 2f;
31 public static float RECLAMATION_SWARM_HP_MULT = 2f;
32 public static float RECLAMATION_SWARM_FRAGMENT_SIZE_MULT = 0.67f;
33
34
35
36 protected float elapsed = 0f;
37 protected ShipAPI primary = null;
38 protected List<ShipAPI> pieces = new ArrayList<>();
39 protected List<ShipAPI> swarms = new ArrayList<>();
40 protected float delay;
41 protected float fadeOutTime;
42 protected float origMaxSpeed = 500f;
43
44 protected IntervalUtil interval = new IntervalUtil(0.075f, 0.125f);
45 protected IntervalUtil interval2 = new IntervalUtil(0.075f, 0.125f);
46 protected boolean spawnedSwarms = false;
47
49 this.delay = delay;
50
51 this.primary = ship;
52 for (ShipAPI curr : Global.getCombatEngine().getShips()) {
53 if (curr.getFleetMember() == ship.getFleetMember()) {
54 pieces.add(curr);
55 }
56 }
57
58 switch (ship.getHullSize()) {
59 case CAPITAL_SHIP:
60 this.fadeOutTime = 15f;
61 break;
62 case CRUISER:
63 this.fadeOutTime = 12f;
64 break;
65 case DESTROYER:
66 this.fadeOutTime = 9f;
67 break;
68 case FRIGATE:
69 this.fadeOutTime = 7f;
70 break;
71 default:
72 this.fadeOutTime = 7f;
73 break;
74 }
75
76 this.fadeOutTime += 3f;
77
79
80 for (ShipAPI curr : pieces) {
82 }
83 }
84
85 public List<ShipAPI> getPieces() {
86 return pieces;
87 }
88
89 @Override
90 public void advance(float amount, List<InputEventAPI> events) {
91 if (Global.getCombatEngine().isPaused()) return;
92
93 elapsed += amount;
94 if (elapsed < delay) return;
95
96
98
99 float progress = (elapsed - delay) / fadeOutTime;
100 if (progress < 0f) progress = 0f;
101 if (progress > 1f) progress = 1f;
102
103
104 float remaining = fadeOutTime - (elapsed - delay);
105
106
107 if (elapsed > delay + 2f && remaining > 4f) {
108 spawnSwarms(amount);
109 }
110
111 boolean first = true;
112 boolean anyInEngine = false;
113 for (ShipAPI ship : pieces) {
114 if (!engine.isInEngine(ship)) continue;
115 anyInEngine = true;
116
117 Vector2f vel = ship.getVelocity();
118 Vector2f acc = new Vector2f(vel);
119 if (acc.length() != 0) {
120 acc.normalise();
121 acc.scale(-1f);
122 acc.scale(amount * ship.getDeceleration());
123 Vector2f.add(vel, acc, vel);
124 float speed = vel.length();
125 if (speed <= 1 || speed < acc.length()) {
126 vel.set(0, 0);
127 }
128 }
129
130 float alpha = 1f;
131 if (progress > 0.5f) {
132 alpha = (1f - progress) * 2f;
133 }
134
135 ship.setAlphaMult(alpha);
136
137 if (first) {
138 Global.getSoundPlayer().playLoop("reclamation_loop", ship, 1f, 1f, ship.getLocation(), ship.getVelocity());
139 first = false;
140 }
141
142 if (false) {
143 float jitterLevel = 1f - progress;
144 if (fadeOutTime <= 4f) {
145 if (jitterLevel < 0.5f) {
146 jitterLevel *= 2f;
147 } else {
148 jitterLevel = (1f - jitterLevel) * 2f;
149 }
150 } else {
151 if (jitterLevel < 0.5f) {
152 jitterLevel *= 2f;
153 } else if (remaining <= 2f) {
154 jitterLevel = remaining / 2f;
155 } else {
156 jitterLevel = 1f;
157 }
158 }
159 jitterLevel = (float) Math.sqrt(jitterLevel);
160
161 //float jitterRange = 1f - progress;
162 float jitterRange = 1f;
163 if (remaining < 2f) {
164 jitterRange = remaining / 2f;
165 } else {
166 jitterRange = (elapsed - delay) / Math.max(1f, fadeOutTime - 2f);
167 }
168 float maxRangeBonus = 25f;
169 float jitterRangeBonus = jitterRange * maxRangeBonus;
170
172 c = Misc.setAlpha(c, 127);
173
174 ship.setJitter(this, c, jitterLevel, 3, 0f, jitterRangeBonus);
175 }
176
177 spawnParticles(ship, amount, progress);
178 }
179
180 if (elapsed > fadeOutTime + delay || !anyInEngine) {
181 for (ShipAPI ship : pieces) {
182 engine.removeEntity(ship);
183 ship.setAlphaMult(0f);
184 }
185 engine.removePlugin(this);
186 }
187 }
188
189 protected void spawnParticles(ShipAPI ship, float amount, float progress) {
190 if (ship == null) return;
191
192 float remaining = fadeOutTime - (elapsed - delay);
193
194 interval.advance(amount);
195 if (interval.intervalElapsed()) {
197
199 c = Misc.setAlpha(c, 50);
200 float baseDuration = 2f;
201 Vector2f vel = new Vector2f(ship.getVelocity());
202 //float size = ship.getCollisionRadius() * 0.35f;
203 float size = ship.getCollisionRadius() * 0.33f;
204
205 float extraDur = 0f;
206 if (remaining < 1f) extraDur = 1f;
207
208 //for (int i = 0; i < 3; i++) {
209 for (int i = 0; i < 11; i++) {
210 Vector2f point = new Vector2f(ship.getLocation());
211 point = Misc.getPointWithinRadiusUniform(point, ship.getCollisionRadius() * 0.75f, Misc.random);
212 float dur = baseDuration + baseDuration * (float) Math.random();
213 dur += extraDur;
214 float nSize = size;
215 Vector2f pt = Misc.getPointWithinRadius(point, nSize * 0.5f);
216 Vector2f v = Misc.getUnitVectorAtDegreeAngle((float) Math.random() * 360f);
217 v.scale(nSize + nSize * (float) Math.random() * 0.5f);
218 v.scale(0.2f);
219 Vector2f.add(vel, v, v);
220
221 float maxSpeed = nSize * 1.5f * 0.2f;
222 float minSpeed = nSize * 1f * 0.2f;
223 float overMin = v.length() - minSpeed;
224 if (overMin > 0) {
225 float durMult = 1f - overMin / (maxSpeed - minSpeed);
226 if (durMult < 0.1f) durMult = 0.1f;
227 dur *= 0.5f + 0.5f * durMult;
228 }
229 engine.addNegativeNebulaParticle(pt, v, nSize * 1f, 2f,
230 0.5f / dur, 0f, dur, c);
231 }
232 }
233 }
234
235 protected void spawnSwarms(float amount) {
236 if (!spawnedSwarms) {
237 int numSwarms = 3;
238
239 for (SwarmConstructableVariant curr : ConstructionSwarmSystemScript.CONSTRUCTABLE) {
240 if (curr.variantId.equals(primary.getVariant().getHullVariantId())) {
241 numSwarms = (int) Math.round(curr.cr * 100f);
242 break;
243 }
244 }
245
246 for (int i = 0; i < numSwarms; i++) {
247 ShipAPI curr = launchSwarm();
248 swarms.add(curr);
249 }
250 spawnedSwarms = true;
251 }
252
253 interval2.advance(amount * 2f);
254 if (interval2.intervalElapsed()) {
256 picker.addAll(pieces);
257
258 for (ShipAPI curr : swarms) {
260 if (swarm == null) continue;
261 if (swarm.getNumActiveMembers() > swarm.params.baseMembersToMaintain) continue;
262
263 SwarmMember p = swarm.addMember();
264
265 ShipAPI piece = picker.pick();
266 if (piece == null) continue;
267
268 Vector2f loc = Misc.getPointWithinRadius(piece.getLocation(), piece.getCollisionRadius() * 0.5f);
269 p.loc.set(loc);
270 p.fader.setDurationIn(0.3f);
271 }
272
273 }
274 }
275
276 protected ShipAPI launchSwarm() {
278
281 manager.setSuppressDeploymentMessages(true);
282
283 Vector2f loc = primary.getLocation();
284 float facing = (float) Math.random() * 360f;
285
286 ShipAPI fighter = manager.spawnShipOrWing(wingId, loc, facing, 0f, null);
287 fighter.getWing().setSourceShip(primary);
288
289 manager.setSuppressDeploymentMessages(false);
290
291 fighter.getMutableStats().getMaxSpeed().modifyMult("construction_swarm", RECLAMATION_SWARM_SPEED_MULT);
292
293 Vector2f takeoffVel = Misc.getUnitVectorAtDegreeAngle(facing);
294 takeoffVel.scale(fighter.getMaxSpeed() * 1f);
295
296 fighter.setDoNotRender(true);
297 fighter.setExplosionScale(0f);
298 fighter.setHulkChanceOverride(0f);
300 fighter.getArmorGrid().clearComponentMap(); // no damage to weapons/engines
301 Vector2f.add(fighter.getVelocity(), takeoffVel, fighter.getVelocity());
302
304 RoilingSwarmEffect.getFlockingMap().remove(swarm.params.flockingClass, swarm);
305 swarm.params.flockingClass = FragmentSwarmHullmod.RECLAMATION_SWARM_FLOCKING_CLASS;
306 RoilingSwarmEffect.getFlockingMap().add(swarm.params.flockingClass, swarm);
307 swarm.params.memberExchangeClass = FragmentSwarmHullmod.RECLAMATION_SWARM_EXCHANGE_CLASS;
308
309
310 //swarm.params.flashFringeColor = VoltaicDischargeOnFireEffect.EMP_FRINGE_COLOR;
311 swarm.params.flashFrequency = 5f;
312 swarm.params.flashProbability = 1f;
313
314 // brownish/rusty
315 //swarm.params.flashFringeColor = new Color(255,95,50,50);
316
317 swarm.params.flashFringeColor = new Color(255,70,30,50);
318 swarm.params.flashCoreRadiusMult = 0f;
319
320 swarm.params.springStretchMult = 1f;
321
322 //swarm.params.baseSpriteSize *= RECLAMATION_SWARM_FRAGMENT_SIZE_MULT;
323 //swarm.params.flashFringeColor = VoltaicDischargeOnFireEffect.EMP_FRINGE_COLOR;
324
325 float collisionMult = RECLAMATION_SWARM_COLLISION_MULT;
326 float hpMult = RECLAMATION_SWARM_HP_MULT;
327
328 for (SegmentAPI s : fighter.getExactBounds().getOrigSegments()) {
329 s.getP1().scale(collisionMult);
330 s.getP2().scale(collisionMult);
331 s.set(s.getP1().x, s.getP1().y, s.getP2().x, s.getP2().y);
332 }
333 fighter.setCollisionRadius(fighter.getCollisionRadius() * collisionMult);
334
335 fighter.setMaxHitpoints(fighter.getMaxHitpoints() * hpMult);
336 fighter.setHitpoints(fighter.getHitpoints() * hpMult);
337
338 swarm.params.maxOffset *= RECLAMATION_SWARM_RADIUS_MULT;
339
340 swarm.params.initialMembers = 0;
341 swarm.params.baseMembersToMaintain = 50;
342
343// int transfer = Math.min(numFragments, sourceSwarm.getNumActiveMembers());
344// if (transfer > 0) {
345// loc = new Vector2f(takeoffVel);
346// loc.scale(0.5f);
347// Vector2f.add(loc, fighter.getLocation(), loc);
348// sourceSwarm.transferMembersTo(swarm, transfer, loc, 100f);
349// }
350//
351// int add = numFragments - transfer;
352// if (add > 0) {
353// swarm.addMembers(add);
354// }
355
356 return fighter;
357
358 }
359}
360
361
362
363
364
365
366
367
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:49
static CombatEngineAPI getCombatEngine()
Definition Global.java:69
void modifyMult(String source, float value)
static RoilingSwarmEffect getSwarmFor(CombatEntityAPI entity)
void setDurationIn(float durationIn)
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
Definition Misc.java:1196
static Color setAlpha(Color color, int alpha)
Definition Misc.java:1316
static Vector2f getPointWithinRadius(Vector2f from, float r)
Definition Misc.java:711
static Vector2f getPointWithinRadiusUniform(Vector2f from, float r, Random random)
Definition Misc.java:722
void playLoop(String id, Object playingEntity, float pitch, float volume, Vector2f loc, Vector2f vel)
List< SegmentAPI > getOrigSegments()
CombatFleetManagerAPI getFleetManager(FleetSide side)
void removeEntity(CombatEntityAPI entity)
void removePlugin(EveryFrameCombatPlugin plugin)
void addNegativeNebulaParticle(Vector2f loc, Vector2f vel, float size, float endSizeMult, float rampUpFraction, float fullBrightnessFraction, float totalDuration, Color color)
ShipAPI spawnShipOrWing(String specId, Vector2f location, float facing)
void setSuppressDeploymentMessages(boolean suppressDeploymentMessages)
void setSourceShip(ShipAPI sourceShip)
MutableShipStatsAPI getMutableStats()
void setMaxHitpoints(float maxArmor)
void setDoNotRender(boolean doNotRender)
void setImpactVolumeMult(float impactVolumeMult)
void setExplosionScale(float explosionScale)
void setHulkChanceOverride(float hulkChanceOverride)