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