Starsector API
Loading...
Searching...
No Matches
RealityDisruptorChargeGlow.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.combat;
2
3import java.util.Iterator;
4import java.util.List;
5
6import java.awt.Color;
7
8import org.lwjgl.util.vector.Vector2f;
9
10import com.fs.starfarer.api.GameState;
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.combat.CollisionClass;
13import com.fs.starfarer.api.combat.CombatEngineAPI;
14import com.fs.starfarer.api.combat.CombatEngineLayers;
15import com.fs.starfarer.api.combat.CombatEntityAPI;
16import com.fs.starfarer.api.combat.DamageType;
17import com.fs.starfarer.api.combat.DamagingProjectileAPI;
18import com.fs.starfarer.api.combat.EmpArcEntityAPI;
19import com.fs.starfarer.api.combat.MissileAPI;
20import com.fs.starfarer.api.combat.ShipAPI;
21import com.fs.starfarer.api.combat.ViewportAPI;
22import com.fs.starfarer.api.combat.WeaponAPI;
23import com.fs.starfarer.api.combat.listeners.AdvanceableListener;
24import com.fs.starfarer.api.util.IntervalUtil;
25import com.fs.starfarer.api.util.Misc;
26
32
33 public static enum EMPArcHitType {
34 SOURCE,
35 DEST,
36 DEST_NO_TARGET,
37 INIMICAL_EMANATION,
38 }
39
40 public static float ARC_RATE_MULT = 2f;
41
42 //public static int MAX_ARC_RANGE = 300;
43 public static int MAX_ARC_RANGE = 600;
44 //public static int ARCS_ON_HIT = 15;
45
46 public static float REPAIR_RATE_MULT = 0.5f;
47 public static float REPAIR_RATE_DEBUFF_DUR = 5f;
48
51
52
53 public static Object STATUS_KEY = new Object();
54
55
56 public static class RDRepairRateDebuff implements AdvanceableListener {
57 public static String DEBUFF_ID = "reality_disruptor_repair_debuff";
58
59 public ShipAPI ship;
60 public float dur = REPAIR_RATE_DEBUFF_DUR;
61 public RDRepairRateDebuff(ShipAPI ship, float dur) {
62 this.ship = ship;
63 this.dur = dur;
64
67 }
68
69 public void resetDur(float dur) {
70 //dur = REPAIR_RATE_DEBUFF_DUR;
71 this.dur = Math.max(this.dur, dur);
72 }
73
74 public void advance(float amount) {
75 dur -= amount;
76
80 Global.getSettings().getSpriteName("ui", "icon_tactical_reality_disruptor"),
81 "REALITY DISRUPTED", "SLOWER REPAIRS: " + (int)Math.max(1, Math.round(dur)) + " SEC", true);
82 }
83
84 if (dur <= 0) {
85 ship.removeListener(this);
88 }
89 }
90 }
91
92
93
94 protected WeaponAPI weapon;
96 protected IntervalUtil interval = new IntervalUtil(0.1f, 0.2f);
97 protected IntervalUtil arcInterval = new IntervalUtil(0.17f, 0.23f);
98 protected float delay = 1f;
99
101 super();
102 this.weapon = weapon;
103 arcInterval = new IntervalUtil(0.17f, 0.23f);
104 delay = 0.5f;
105 setSpriteSheetKey("fx_particles2");
106 }
107
109 this.proj = proj;
110 }
111
112 public void advance(float amount) {
113 if (Global.getCombatEngine().isPaused()) return;
114 if (proj != null) {
116 } else {
118 }
119 super.advance(amount);
120
121 boolean keepSpawningParticles = isWeaponCharging(weapon) ||
122 (proj != null && !isProjectileExpired(proj) && !proj.isFading());
123 if (keepSpawningParticles) {
124 interval.advance(amount);
125 if (interval.intervalElapsed()) {
127 }
128 }
129
130 if (proj != null && !isProjectileExpired(proj) && !proj.isFading()) {
131 delay -= amount;
132 if (delay <= 0) {
134 if (arcInterval.intervalElapsed()) {
135 spawnArc();
136 }
137 }
138 }
139 if (proj != null) {
140 Global.getSoundPlayer().playLoop("realitydisruptor_loop", proj, 1f, 1f * proj.getBrightness(),
142 }
143
144// if (proj != null) {
145// proj.setFacing(proj.getFacing() + 30f * amount);
146// }
147 }
148
149 @Override
151 // pass in proj as last argument to have particles rotate
152 super.render(layer, viewport, null);
153 }
154
155 public boolean isExpired() {
156 boolean keepSpawningParticles = isWeaponCharging(weapon) ||
157 (proj != null && !isProjectileExpired(proj) && !proj.isFading());
158 return super.isExpired() && (!keepSpawningParticles || (!weapon.getShip().isAlive() && proj == null));
159 }
160
161
162 public float getRenderRadius() {
163 return 500f;
164 }
165
166
167 @Override
168 protected float getGlobalAlphaMult() {
169 if (proj != null && proj.isFading()) {
170 return proj.getBrightness();
171 }
172 return super.getGlobalAlphaMult();
173 }
174
175
176
177 public void spawnArc() {
179
180 float emp = proj.getEmpAmount();
181 float dam = proj.getDamageAmount();
182
183 CombatEntityAPI target = findTarget(proj, weapon, engine);
184 float thickness = 20f;
185 float coreWidthMult = 0.67f;
186 Color color = weapon.getSpec().getGlowColor();
187 //color = new Color(255,100,100,255);
188 if (target != null) {
190 target,
192 dam,
193 emp, // emp
194 100000f, // max range
195 "realitydisruptor_emp_impact",
196 thickness, // thickness
197 color,
198 new Color(255,255,255,255)
199 );
200 arc.setCoreWidthOverride(thickness * coreWidthMult);
201
202 spawnEMPParticles(EMPArcHitType.SOURCE, proj, proj.getLocation(), null);
203 spawnEMPParticles(EMPArcHitType.DEST, proj, arc.getTargetLocation(), target);
204
205 if (target instanceof ShipAPI) {
206 ShipAPI s = (ShipAPI) target;
207 List<RDRepairRateDebuff> listeners = s.getListeners(RDRepairRateDebuff.class);
208 if (listeners.isEmpty()) {
209 s.addListener(new RDRepairRateDebuff(s, REPAIR_RATE_DEBUFF_DUR));
210 } else {
211 listeners.get(0).resetDur(REPAIR_RATE_DEBUFF_DUR);
212 }
213 }
214
215 } else {
216 Vector2f from = new Vector2f(proj.getLocation());
217 Vector2f to = pickNoTargetDest(proj, weapon, engine);
218 EmpArcEntityAPI arc = engine.spawnEmpArcVisual(from, null, to, null, thickness, color, Color.white);
219 arc.setCoreWidthOverride(thickness * coreWidthMult);
220 Global.getSoundPlayer().playSound("realitydisruptor_emp_impact", 1f, 1f, to, new Vector2f());
221
222 spawnEMPParticles(EMPArcHitType.SOURCE, proj, from, null);
223 spawnEMPParticles(EMPArcHitType.DEST_NO_TARGET, proj, to, null);
224 }
225 }
226
227
228
230 float range = 200f;
231 Vector2f from = projectile.getLocation();
232 Vector2f dir = Misc.getUnitVectorAtDegreeAngle((float) Math.random() * 360f);
233 dir.scale(range);
234 Vector2f.add(from, dir, dir);
235 dir = Misc.getPointWithinRadius(dir, range * 0.25f);
236 return dir;
237 }
238
240 float range = MAX_ARC_RANGE;
241 Vector2f from = projectile.getLocation();
242
243 Iterator<Object> iter = Global.getCombatEngine().getAllObjectGrid().getCheckIterator(from,
244 range * 2f, range * 2f);
245 int owner = weapon.getShip().getOwner();
246 CombatEntityAPI best = null;
247 float minScore = Float.MAX_VALUE;
248 while (iter.hasNext()) {
249 Object o = iter.next();
250 if (!(o instanceof MissileAPI) &&
252 !(o instanceof ShipAPI)) continue;
254 if (other.getOwner() == owner) continue;
255
256 if (other instanceof ShipAPI) {
257 ShipAPI otherShip = (ShipAPI) other;
258 if (otherShip.isHulk()) continue;
259 if (otherShip.isPhased()) continue;
260 if (!otherShip.isTargetable()) continue;
261 }
262 if (other.getCollisionClass() == CollisionClass.NONE) continue;
263
264 float radius = Misc.getTargetingRadius(from, other, false);
265 float dist = Misc.getDistance(from, other.getLocation()) - radius - 50f;
266 if (dist > range) continue;
267
268 //float angleTo = Misc.getAngleInDegrees(from, other.getLocation());
269 //float score = Misc.getAngleDiff(weapon.getCurrAngle(), angleTo);
270 float score = dist;
271
272 if (score < minScore) {
273 minScore = score;
274 best = other;
275 }
276 }
277 return best;
278 }
279
281 //CombatEngineAPI engine = Global.getCombatEngine();
283
284// float b = 1f;
285// color = Misc.scaleAlpha(color, b);
286 //undercolor = Misc.scaleAlpha(undercolor, b);
287
288 float size = 50f;
289 float underSize = 75f;
290 //underSize = 100f;
291
292 float in = 0.25f;
293 float out = 0.75f;
294
295 out *= 3f;
296
297 float velMult = 0.2f;
298
300 size *= 0.25f + weapon.getChargeLevel() * 0.75f;
301 }
302
303 addDarkParticle(size, in, out, 1f, size * 0.5f * velMult, 0f, color);
304 randomizePrevParticleLocation(size * 0.33f);
305
306 if (proj != null) {
307 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(proj.getFacing() + 180f);
308 //size = 40f;
309 if (proj.getElapsed() > 0.2f) {
310 addDarkParticle(size, in, out, 1.5f, size * 0.5f * velMult, 0f, color);
311 Vector2f offset = new Vector2f(dir);
312 offset.scale(size * 0.6f + (float) Math.random() * 0.2f);
313 Vector2f.add(prev.offset, offset, prev.offset);
314 }
315 if (proj.getElapsed() > 0.4f) {
316 addDarkParticle(size * 1f, in, out, 1.3f, size * 0.5f * velMult, 0f, color);
317 Vector2f offset = new Vector2f(dir);
318 offset.scale(size * 1.2f + (float) Math.random() * 0.2f);
319 Vector2f.add(prev.offset, offset, prev.offset);
320 }
321 if (proj.getElapsed() > 0.6f) {
322 addDarkParticle(size * .8f, in, out, 1.1f, size * 0.5f * velMult, 0f, color);
323 Vector2f offset = new Vector2f(dir);
324 offset.scale(size * 1.6f + (float) Math.random() * 0.2f);
325 Vector2f.add(prev.offset, offset, prev.offset);
326 }
327
328 if (proj.getElapsed() > 0.8f) {
329 addDarkParticle(size * .8f, in, out, 1.1f, size * 0.5f * velMult, 0f, color);
330 Vector2f offset = new Vector2f(dir);
331 offset.scale(size * 2.0f + (float) Math.random() * 0.2f);
332 Vector2f.add(prev.offset, offset, prev.offset);
333 }
334// int num = (int) Math.round(proj.getElapsed() / 0.5f * 10f);
335// if (num > 15) num = 15;
336// for (int i = 0; i < num; i++) {
337// addDarkParticle(size, in, out, 1f, size * 0.5f, 0f, color);
338// Vector2f offset = new Vector2f(dir);
339// offset.scale(size * 0.1f * i);
340// Vector2f.add(prev.offset, offset, prev.offset);
341// }
342 }
343
344// UNDERCOLOR = new Color(100, 0, 100, 100);
345// UNDERCOLOR = NSProjEffect.EXPLOSION_UNDERCOLOR;
346
347 // defaults:
348 //public static Color EXPLOSION_UNDERCOLOR = new Color(100, 0, 25, 100);
349 //public static Color STANDARD_RIFT_COLOR = new Color(100,60,255,255);
350
351 //"glowColor":[100,200,255,255], #ion cannon
352// RIFT_COLOR = new Color(100, 200, 255, 255);
353
354// UNDERCOLOR = NSProjEffect.EXPLOSION_UNDERCOLOR;
355// RIFT_COLOR = NSProjEffect.STANDARD_RIFT_COLOR;
356
357// UNDERCOLOR = new Color(255, 0, 25, 100);
358// UNDERCOLOR = new Color(100, 0, 25, 100);
359
360 addParticle(underSize * 0.5f, in, out, 1.5f * 3f, 0f, 0f, UNDERCOLOR);
361 randomizePrevParticleLocation(underSize * 0.67f);
362 addParticle(underSize * 0.5f, in, out, 1.5f * 3f, 0f, 0f, UNDERCOLOR);
363 randomizePrevParticleLocation(underSize * 0.67f);
364
365// float facing = weapon.getCurrAngle();
366// if (proj != null) facing = proj.getFacing();
367// Vector2f dir = Misc.getUnitVectorAtDegreeAngle(facing + 210f * ((float) Math.random() - 0.5f));
368// dir.scale(underSize * 0.25f * (float) Math.random());
369// Vector2f.add(prev.offset, dir, prev.offset);
370 }
371
372 public static void spawnEMPParticles(EMPArcHitType type, DamagingProjectileAPI proj, Vector2f point, CombatEntityAPI target) {
374
376
377 float size = 30f;
378 float baseDuration = 1.5f;
379 Vector2f vel = new Vector2f();
380 int numNegative = 5;
381 int numSwirly = 7;
382 switch (type) {
383 case DEST:
384 size = 50f;
385 vel.set(target.getVelocity());
386 if (vel.length() > 100f) {
387 vel.scale(100f / vel.length());
388 }
389 break;
390 case DEST_NO_TARGET:
391 break;
392 case INIMICAL_EMANATION:
393 numNegative = 5;
394 numSwirly = 7;
395 //numSwirly = 12;
396 size = 25;
398 baseDuration = 1f;
399 if (target != null && !(target instanceof MissileAPI)) {
400 vel.set(target.getVelocity());
401// if (vel.length() > 100f) {
402// vel.scale(100f / vel.length());
403// }
404 }
405 break;
406 case SOURCE:
407 size = 40f;
408 numNegative = 10;
409 break;
410 }
411 boolean inimical = type == EMPArcHitType.INIMICAL_EMANATION;
412 //dir.negate();
413 //numNegative = 0;
414 for (int i = 0; i < numNegative; i++) {
415 float dur = baseDuration + baseDuration * (float) Math.random();
416 //float nSize = size * (1f + 0.0f * (float) Math.random());
417 //float nSize = size * (0.75f + 0.5f * (float) Math.random());
418 float nSize = size;
419 if (type == EMPArcHitType.SOURCE) {
420 nSize *= 1.5f;
421 }
422 float scatterMult = 1f;
423 if (inimical) scatterMult = 0.25f;
424 Vector2f pt = Misc.getPointWithinRadius(point, nSize * 0.5f * scatterMult);
425 Vector2f v = Misc.getUnitVectorAtDegreeAngle((float) Math.random() * 360f);
426 v.scale(nSize + nSize * (float) Math.random() * 0.5f);
427 v.scale(0.2f);
428
429 float endSizeMult = 2f;
430 if (type == EMPArcHitType.SOURCE) {
431 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(proj.getFacing() + 180f);
432 pt = Misc.getPointWithinRadius(point, nSize * 0f);
433 Vector2f offset = new Vector2f(dir);
434 offset.scale(size * 0.2f * i);
435 Vector2f.add(pt, offset, pt);
436 endSizeMult = 1.5f;
437 v.scale(0.5f);
438 }
439 Vector2f.add(vel, v, v);
440
441 float maxSpeed = nSize * 1.5f * 0.2f;
442 float minSpeed = nSize * 1f * 0.2f;
443 float overMin = v.length() - minSpeed;
444 if (overMin > 0) {
445 float durMult = 1f - overMin / (maxSpeed - minSpeed);
446 if (durMult < 0.1f) durMult = 0.1f;
447 dur *= 0.5f + 0.5f * durMult;
448 }
449
450// if (type == EMPArcHitType.DEST || type == EMPArcHitType.DEST_NO_TARGET) {
451// v.set(0f, 0f);
452// }
453
454 float rampUp = 0.25f / dur;
455 if (inimical) {
456 rampUp = 0f;
457 //nSize *= 2f;
458 }
459 engine.addNegativeNebulaParticle(pt, v, nSize * 1f, endSizeMult,
460 //engine.addNegativeSwirlyNebulaParticle(pt, v, nSize * 1f, endSizeMult,
461 rampUp, 0f, dur, color);
462 }
463
464 float dur = baseDuration;
465 float rampUp = 0.5f / dur;
466 if (inimical) {
467 //numSwirly = 15;
468 //rampUp = 0.1f;
469 rampUp = 0f;
470 }
471 color = UNDERCOLOR;
472// if (inimical) {
473// color = DwellerShroud.SHROUD_COLOR;
474// }
475 for (int i = 0; i < numSwirly; i++) {
476 Vector2f loc = new Vector2f(point);
477 float scatterMult = 1f;
478 if (inimical) scatterMult = 0.5f;
479 loc = Misc.getPointWithinRadius(loc, size * 1f * scatterMult);
480 float s = size * 4f * (0.5f + (float) Math.random() * 0.5f);
481 if (inimical) {
482 //size *= 2f;
483 //size *= 1.25f;
484 //size *= 1.1f;
485 }
486 engine.addSwirlyNebulaParticle(loc, vel, s, 1.5f, rampUp, 0f, dur, color, false);
487 }
488 }
489
490
494
495 public static boolean isWeaponCharging(WeaponAPI weapon) {
496 return weapon.getChargeLevel() > 0 && weapon.getCooldownRemaining() <= 0;
497 }
498}
499
500
501
502
503
504
static SettingsAPI getSettings()
Definition Global.java:57
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:49
static CombatEngineAPI getCombatEngine()
Definition Global.java:69
static GameState getCurrentState()
Definition Global.java:27
void modifyMult(String source, float value)
ParticleData addDarkParticle(float baseSize, float durIn, float durOut, float endSizeMult, float maxDriftVel, float maxAngVel, Color color)
ParticleData addParticle(float baseSize, float durIn, float durOut, float endSizeMult, float maxDriftVel, float maxAngVel, Color color)
static void spawnEMPParticles(EMPArcHitType type, DamagingProjectileAPI proj, Vector2f point, CombatEntityAPI target)
Vector2f pickNoTargetDest(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine)
void render(CombatEngineLayers layer, ViewportAPI viewport)
CombatEntityAPI findTarget(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine)
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
Definition Misc.java:1196
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
static float getTargetingRadius(Vector2f from, CombatEntityAPI target, boolean considerShield)
Definition Misc.java:1349
static Vector2f getPointWithinRadius(Vector2f from, float r)
Definition Misc.java:711
String getSpriteName(String category, String id)
void playLoop(String id, Object playingEntity, float pitch, float volume, Vector2f loc, Vector2f vel)
SoundAPI playSound(String id, float pitch, float volume, Vector2f loc, Vector2f vel)
Iterator< Object > getCheckIterator(Vector2f loc, float checkWidth, float checkHeight)
EmpArcEntityAPI spawnEmpArcVisual(Vector2f from, CombatEntityAPI fromAnchor, Vector2f to, CombatEntityAPI toAnchor, float thickness, Color fringe, Color core)
void maintainStatusForPlayerShip(Object key, String spriteName, String title, String data, boolean isDebuff)
boolean isEntityInPlay(CombatEntityAPI entity)
void addSwirlyNebulaParticle(Vector2f loc, Vector2f vel, float size, float endSizeMult, float rampUpFraction, float fullBrightnessFraction, float totalDuration, Color color, boolean expandAsSqrt)
void addNegativeNebulaParticle(Vector2f loc, Vector2f vel, float size, float endSizeMult, float rampUpFraction, float fullBrightnessFraction, float totalDuration, Color color)
EmpArcEntityAPI spawnEmpArc(ShipAPI damageSource, Vector2f point, CombatEntityAPI pointAnchor, CombatEntityAPI empTargetEntity, DamageType damageType, float damAmount, float empDamAmount, float maxRange, String impactSoundId, float thickness, Color fringe, Color core)
void setCoreWidthOverride(float coreWidthOverride)
MutableShipStatsAPI getMutableStats()
void addListener(Object listener)
void removeListener(Object listener)
< T > List< T > getListeners(Class< T > c)