Starsector API
Loading...
Searching...
No Matches
CryofluxTransducerEffect.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.combat;
2
3import java.util.ArrayList;
4import java.util.EnumSet;
5import java.util.Iterator;
6import java.util.List;
7
8import java.awt.Color;
9
10import org.lwjgl.util.vector.Vector2f;
11
12import com.fs.starfarer.api.Global;
13import com.fs.starfarer.api.combat.BaseCombatLayeredRenderingPlugin;
14import com.fs.starfarer.api.combat.CombatEngineAPI;
15import com.fs.starfarer.api.combat.CombatEngineLayers;
16import com.fs.starfarer.api.combat.CombatEntityAPI;
17import com.fs.starfarer.api.combat.DamagingProjectileAPI;
18import com.fs.starfarer.api.combat.EveryFrameWeaponEffectPlugin;
19import com.fs.starfarer.api.combat.OnFireEffectPlugin;
20import com.fs.starfarer.api.combat.OnHitEffectPlugin;
21import com.fs.starfarer.api.combat.ShipAPI;
22import com.fs.starfarer.api.combat.ViewportAPI;
23import com.fs.starfarer.api.combat.WeaponAPI;
24import com.fs.starfarer.api.combat.listeners.ApplyDamageResultAPI;
25import com.fs.starfarer.api.graphics.SpriteAPI;
26import com.fs.starfarer.api.util.FaderUtil;
27import com.fs.starfarer.api.util.Misc;
28
39
41 }
42
43 protected String getLoopId() {
44 return "cryoflamer_loop";
45 }
46
47 protected void playImpactSound(ApplyDamageResultAPI damageResult, Vector2f point, Vector2f vel) {
48 Misc.playSound(damageResult, point, vel,
49 "cryoflamer_hit_shield_light",
50 "cryoflamer_hit_shield_solid",
51 "cryoflamer_hit_shield_heavy",
52 "cryoflamer_hit_light",
53 "cryoflamer_hit_solid",
54 "cryoflamer_hit_heavy");
55 }
56
57 protected String getParticleSpriteCat() {
58 return "misc";
59 }
60 protected String getParticleSpriteKey() {
61 return "nebula_particles";
62 }
63 protected float getParticleScale() {
64 return 1f;
65 }
67 return 1f;
68 }
69 protected int getNumParticles() {
70 return 7;
71 }
72 protected float getThresholdDist() {
73 return 20f;
74 }
75
76 protected List<CryofluxTransducerEffect> trails;
77 public void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon) {
78 if (trails == null) return;
79
80 Iterator<CryofluxTransducerEffect> iter = trails.iterator();
81 while (iter.hasNext()) {
82 if (iter.next().isExpired()) iter.remove();
83 }
84
85 // sound loop playback
86 if (weapon.getShip() != null) {
87 float maxRange = weapon.getRange();
88 ShipAPI ship = weapon.getShip();
89 Vector2f com = new Vector2f();
90 float weight = 0f;
91 float totalDist = 0f;
92 Vector2f source = weapon.getLocation();
93 for (CryofluxTransducerEffect curr : trails) {
94 if (curr.proj != null) {
95 Vector2f.add(com, curr.proj.getLocation(), com);
96 weight += curr.proj.getBrightness();
97 totalDist += Misc.getDistance(source, curr.proj.getLocation());
98 }
99 }
100 if (weight > 0.1f) {
101 com.scale(1f / weight);
102 float volume = Math.min(weight, 1f);
103 if (trails.size() > 0) {
104 totalDist /= (float) trails.size();
105 float mult = totalDist / Math.max(maxRange, 1f);
106 mult = 1f - mult;
107 if (mult > 1f) mult = 1f;
108 if (mult < 0f) mult = 0f;
109 mult = (float) Math.sqrt(mult);
110 volume *= mult;
111 }
112 Global.getSoundPlayer().playLoop(getLoopId(), ship, 1f, volume, com, ship.getVelocity());
113 }
114 }
115
116
117 //System.out.println("Trails: " + trails.size());
118 float numIter = 1f; // more doesn't actually change anything
119 amount /= numIter;
120 float thresholdDist = getThresholdDist();
121 //thresholdDist = 50f;
122 // drag along the previous projectile, starting with the most recently launched; new ones are added at the start
123 // note: prev is fired before and so is in front of proj
124 for (int i = 0; i < numIter; i++) {
125 for (CryofluxTransducerEffect trail : trails) {
126 //trail.proj.setFacing(trail.proj.getFacing() + 180f * amount);
127 if (trail.prev != null && !trail.prev.isExpired() && Global.getCombatEngine().isEntityInPlay(trail.prev)) {
128 float dist1 = Misc.getDistance(trail.prev.getLocation(), trail.proj.getLocation());
129 if (dist1 < trail.proj.getProjectileSpec().getLength() * 1f) {
130 float maxSpeed = trail.prev.getMoveSpeed() * 0.5f;// * Math.max(0.5f, 1f - trail.prev.getElapsed() * 0.5f);
131 // goal here is to prevent longer shot series (e.g. from Paragon) from moving too unnaturally
132 float e = trail.prev.getElapsed();
133 float t = 0.5f;
134 if (e > t) {
135 maxSpeed *= Math.max(0.25f, 1f - (e - t) * 0.5f);
136 }
137 if (dist1 < thresholdDist && e > t) {
138 maxSpeed *= dist1 / thresholdDist;
139 }
140
141 Vector2f driftTo = Misc.closestPointOnLineToPoint(trail.proj.getLocation(), trail.proj.getTailEnd(), trail.prev.getLocation());
142 float dist = Misc.getDistance(driftTo, trail.prev.getLocation());
143 Vector2f diff = Vector2f.sub(driftTo, trail.prev.getLocation(), new Vector2f());
144 diff = Misc.normalise(diff);
145 diff.scale(Math.min(dist, maxSpeed * amount));
146 Vector2f.add(trail.prev.getLocation(), diff, trail.prev.getLocation());
147 Vector2f.add(trail.prev.getTailEnd(), diff, trail.prev.getTailEnd());
148 }
149 }
150 }
151 }
152 }
153
154
155 public void onHit(DamagingProjectileAPI projectile, CombatEntityAPI target, Vector2f point, boolean shieldHit, ApplyDamageResultAPI damageResult, CombatEngineAPI engine) {
156 Color color = projectile.getProjectileSpec().getFringeColor();
157// Color inverted = NSLanceEffect.getColorForDarkening(color);
158// inverted = Misc.setAlpha(inverted, 50);
159// Color inverted = new Color(255, 255, 100, 50);
160
161 Vector2f vel = new Vector2f();
162 if (target instanceof ShipAPI) {
163 vel.set(target.getVelocity());
164 }
165
166 float size = projectile.getProjectileSpec().getWidth() * 1f;
167 //size = Misc.getHitGlowSize(size, projectile.getDamage().getBaseDamage(), damageResult);
168 float sizeMult = Misc.getHitGlowSize(100f, projectile.getDamage().getBaseDamage(), damageResult) / 100f;
169// sizeMult = 1.5f;
170// System.out.println(sizeMult);
171 float dur = 1f;
172 float rampUp = 0f;
173 Color c = Misc.scaleAlpha(color, projectile.getBrightness());
174 engine.addNebulaParticle(point, vel, size, 5f + 3f * sizeMult,
175 rampUp, 0f, dur, c);
176// engine.addNegativeNebulaParticle(point, vel, size, 2f,
177// rampUp, 0f, dur, inverted);
178// engine.addNegativeParticle(point, vel, size,
179// rampUp, dur, inverted);
180
181 playImpactSound(damageResult, point, vel);
182 }
183
184 public void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
185 String prevKey = "cryo_prev_" + weapon.getShip().getId() + "_" + weapon.getSlot().getId();
187
188 CryofluxTransducerEffect trail = createTrail(projectile, prev);
190 e.getLocation().set(projectile.getLocation());
191
192 engine.getCustomData().put(prevKey, projectile);
193
194 if (trails == null) {
195 trails = new ArrayList<CryofluxTransducerEffect>();
196 }
197 trails.add(0, trail);
198 }
199
203
204
205 public static class ParticleData {
206 public SpriteAPI sprite;
207 public Vector2f offset = new Vector2f();
208 public Vector2f vel = new Vector2f();
209 public float scale = 1f;
210 public DamagingProjectileAPI proj;
211 public float scaleIncreaseRate = 1f;
212 public float turnDir = 1f;
213 public float angle = 1f;
214 public FaderUtil fader;
215
216 public ParticleData(DamagingProjectileAPI proj, CryofluxTransducerEffect effect) {
217 this.proj = proj;
219 //sprite = Global.getSettings().getSprite("misc", "dust_particles");
220 float i = Misc.random.nextInt(4);
221 float j = Misc.random.nextInt(4);
222 sprite.setTexWidth(0.25f);
223 sprite.setTexHeight(0.25f);
224 sprite.setTexX(i * 0.25f);
225 sprite.setTexY(j * 0.25f);
226 sprite.setAdditiveBlend();
227
228 angle = (float) Math.random() * 360f;
229
230 float maxDur = proj.getWeapon().getRange() / proj.getWeapon().getProjectileSpeed();
231 scaleIncreaseRate = 2f / maxDur;
232 scaleIncreaseRate *= effect.getParticleScaleIncreaseRateMult();
233 scale = effect.getParticleScale();
234 //scale = 2f;
235// scale = 0.1f;
236// scaleIncreaseRate = 2.9f / maxDur;
237// scale = 0.1f;
238// scaleIncreaseRate = 2.5f / maxDur;
239// scale = 0.5f;
240
241 turnDir = Math.signum((float) Math.random() - 0.5f) * 60f * (float) Math.random();
242 //turnDir = 0f;
243
244 float driftDir = (float) Math.random() * 360f;
245 vel = Misc.getUnitVectorAtDegreeAngle(driftDir);
246 vel.scale(proj.getProjectileSpec().getWidth() / maxDur * 0.33f);
247
248// offset.x += vel.x * 1f;
249// offset.y += vel.y * 1f;
250 fader = new FaderUtil(0f, 0.25f, 0.5f);
251 fader.fadeIn();
252 }
253
254 public void advance(float amount) {
255 scale += scaleIncreaseRate * amount;
256 if (scale < 1f) {
257 scale += scaleIncreaseRate * amount * 1f;
258 }
259
260 offset.x += vel.x * amount;
261 offset.y += vel.y * amount;
262
263 angle += turnDir * amount;
264
265 fader.advance(amount);
266 }
267 }
268
269 protected List<ParticleData> particles = new ArrayList<ParticleData>();
270
273 protected float baseFacing = 0f;
275 this.proj = proj;
276 this.prev = prev;
277
279
280 int num = getNumParticles();
281 for (int i = 0; i < num; i++) {
282 particles.add(new ParticleData(proj, this));
283 }
284
285 float length = proj.getProjectileSpec().getLength();
286 float width = proj.getProjectileSpec().getWidth();
287
288 float index = 0;
289 for (ParticleData p : particles) {
290 float f = index / (particles.size() - 1);
291 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(proj.getFacing() + 180f);
292 dir.scale(length * f);
293 Vector2f.add(p.offset, dir, p.offset);
294
295 p.offset = Misc.getPointWithinRadius(p.offset, width * 0.5f);
296 //p.scale = 0.25f + 0.75f * (1 - f);
297
298 index++;
299 }
300 }
301
302 public float getRenderRadius() {
303 return 300f;
304 }
305
306
307 protected EnumSet<CombatEngineLayers> layers = EnumSet.of(CombatEngineLayers.ABOVE_SHIPS_AND_MISSILES_LAYER);
308 @Override
309 public EnumSet<CombatEngineLayers> getActiveLayers() {
310 return layers;
311 }
312
313
315 super.init(entity);
316 }
317
318 public void advance(float amount) {
319 if (Global.getCombatEngine().isPaused()) return;
320
322
323 for (ParticleData p : particles) {
324 p.advance(amount);
325 }
326 }
327
328
329 public boolean isExpired() {
331 }
332
333 public Color getParticleColor() {
334 Color color = proj.getProjectileSpec().getFringeColor();
335 color = Misc.setAlpha(color, 50);
336 return color;
337 }
338
340 float x = entity.getLocation().x;
341 float y = entity.getLocation().y;
342
343 //Color color = new Color(100,150,255,50);
344 Color color = getParticleColor();
345 float b = proj.getBrightness();
346 b *= viewport.getAlphaMult();
347
348 for (ParticleData p : particles) {
349 float size = proj.getProjectileSpec().getWidth() * 0.6f;
350 size *= p.scale;
351
352 float alphaMult = 1f;
353 Vector2f offset = p.offset;
354 float diff = Misc.getAngleDiff(baseFacing, proj.getFacing());
355 if (Math.abs(diff) > 0.1f) {
356 offset = Misc.rotateAroundOrigin(offset, diff);
357 }
358 Vector2f loc = new Vector2f(x + offset.x, y + offset.y);
359
360 p.sprite.setAngle(p.angle);
361 p.sprite.setSize(size, size);
362 p.sprite.setAlphaMult(b * alphaMult * p.fader.getBrightness());
363 p.sprite.setColor(color);
364 p.sprite.renderAtCenter(loc.x, loc.y);
365 }
366 }
367
368}
369
370
371
372
static SettingsAPI getSettings()
Definition Global.java:57
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:49
static CombatEngineAPI getCombatEngine()
Definition Global.java:69
void onHit(DamagingProjectileAPI projectile, CombatEntityAPI target, Vector2f point, boolean shieldHit, ApplyDamageResultAPI damageResult, CombatEngineAPI engine)
CryofluxTransducerEffect createTrail(DamagingProjectileAPI projectile, DamagingProjectileAPI prev)
void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon)
void playImpactSound(ApplyDamageResultAPI damageResult, Vector2f point, Vector2f vel)
void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine)
void render(CombatEngineLayers layer, ViewportAPI viewport)
CryofluxTransducerEffect(DamagingProjectileAPI proj, DamagingProjectileAPI prev)
static void playSound(ApplyDamageResultAPI result, Vector2f loc, Vector2f vel, String lightShields, String solidShields, String heavyShields, String lightHull, String solidHull, String heavyHull)
Definition Misc.java:6036
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
Definition Misc.java:1196
static Color setAlpha(Color color, int alpha)
Definition Misc.java:1316
static Vector2f rotateAroundOrigin(Vector2f v, float angle)
Definition Misc.java:1205
static Vector2f closestPointOnLineToPoint(Vector2f p1, Vector2f p2, Vector2f p3)
Definition Misc.java:1877
static float getHitGlowSize(float baseSize, float baseDamage, ApplyDamageResultAPI result)
Definition Misc.java:5353
static float getAngleDiff(float from, float to)
Definition Misc.java:1716
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
static Color scaleAlpha(Color color, float factor)
Definition Misc.java:1309
static Vector2f getPointWithinRadius(Vector2f from, float r)
Definition Misc.java:711
static Vector2f normalise(Vector2f v)
Definition Misc.java:1134
SpriteAPI getSprite(String filename)
void playLoop(String id, Object playingEntity, float pitch, float volume, Vector2f loc, Vector2f vel)
CombatEntityAPI addLayeredRenderingPlugin(CombatLayeredRenderingPlugin plugin)
boolean isEntityInPlay(CombatEntityAPI entity)
void addNebulaParticle(Vector2f loc, Vector2f vel, float size, float endSizeMult, float rampUpFraction, float fullBrightnessFraction, float totalDuration, Color color)