Starsector API
Loading...
Searching...
No Matches
DisintegratorEffect.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.List;
6
7import java.awt.Color;
8
9import org.lwjgl.opengl.GL14;
10import org.lwjgl.util.vector.Vector2f;
11
12import com.fs.starfarer.api.Global;
13import com.fs.starfarer.api.combat.ArmorGridAPI;
14import com.fs.starfarer.api.combat.BaseCombatLayeredRenderingPlugin;
15import com.fs.starfarer.api.combat.CombatEngineAPI;
16import com.fs.starfarer.api.combat.CombatEngineLayers;
17import com.fs.starfarer.api.combat.CombatEntityAPI;
18import com.fs.starfarer.api.combat.DamageType;
19import com.fs.starfarer.api.combat.DamagingProjectileAPI;
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.listeners.ApplyDamageResultAPI;
24import com.fs.starfarer.api.graphics.SpriteAPI;
25import com.fs.starfarer.api.util.FaderUtil;
26import com.fs.starfarer.api.util.IntervalUtil;
27import com.fs.starfarer.api.util.Misc;
28
30
31 // each tick is on average .9 seconds
32 // ticks can't be longer than a second or floating damage numbers separate
33 //public static int NUM_TICKS = 22;
34 public static int NUM_TICKS = 11;
35 public static float TOTAL_DAMAGE = 1000;
36
38 }
39
40 protected float getTotalDamage() {
41 return TOTAL_DAMAGE;
42 }
43 protected int getNumTicks() {
44 return NUM_TICKS;
45 }
46 protected boolean canDamageHull() {
47 return false;
48 }
49
50 public void onHit(DamagingProjectileAPI projectile, CombatEntityAPI target, Vector2f point, boolean shieldHit, ApplyDamageResultAPI damageResult, CombatEngineAPI engine) {
51 if (shieldHit) return;
52 if (projectile.isFading()) return;
53 if (!(target instanceof ShipAPI)) return;
54
55 Vector2f offset = Vector2f.sub(point, target.getLocation(), new Vector2f());
57
58 DisintegratorEffect effect = new DisintegratorEffect(projectile, (ShipAPI) target, offset);
60 e.getLocation().set(projectile.getLocation());
61 }
62
63 public static class ParticleData {
64 public SpriteAPI sprite;
65 public Vector2f offset = new Vector2f();
66 public Vector2f vel = new Vector2f();
67 public float scale = 1f;
68 public float scaleIncreaseRate = 1f;
69 public float turnDir = 1f;
70 public float angle = 1f;
71
72 public float maxDur;
73 public FaderUtil fader;
74 public float elapsed = 0f;
75 public float baseSize;
76
77 public Color color = new Color(100,150,255,35);
78
79 public ParticleData(float baseSize, float maxDur, float endSizeMult) {
80 sprite = Global.getSettings().getSprite("misc", "nebula_particles");
81 //sprite = Global.getSettings().getSprite("misc", "dust_particles");
82 float i = Misc.random.nextInt(4);
83 float j = Misc.random.nextInt(4);
84 sprite.setTexWidth(0.25f);
85 sprite.setTexHeight(0.25f);
86 sprite.setTexX(i * 0.25f);
87 sprite.setTexY(j * 0.25f);
88 sprite.setAdditiveBlend();
89
90 angle = (float) Math.random() * 360f;
91
92 this.maxDur = maxDur;
93 scaleIncreaseRate = endSizeMult / maxDur;
94 if (endSizeMult < 1f) {
95 scaleIncreaseRate = -1f * endSizeMult;
96 }
97 scale = 1f;
98
99 this.baseSize = baseSize;
100 turnDir = Math.signum((float) Math.random() - 0.5f) * 20f * (float) Math.random();
101 //turnDir = 0f;
102
103 float driftDir = (float) Math.random() * 360f;
104 vel = Misc.getUnitVectorAtDegreeAngle(driftDir);
105 //vel.scale(proj.getProjectileSpec().getLength() / maxDur * (0f + (float) Math.random() * 3f));
106 vel.scale(0.25f * baseSize / maxDur * (1f + (float) Math.random() * 1f));
107
108 fader = new FaderUtil(0f, 0.5f, 0.5f);
109 fader.forceOut();
110 fader.fadeIn();
111 }
112
113 public void advance(float amount) {
114 scale += scaleIncreaseRate * amount;
115
116 offset.x += vel.x * amount;
117 offset.y += vel.y * amount;
118
119 angle += turnDir * amount;
120
121 elapsed += amount;
122 if (maxDur - elapsed <= fader.getDurationOut() + 0.1f) {
123 fader.fadeOut();
124 }
125 fader.advance(amount);
126 }
127 }
128
129 protected List<ParticleData> particles = new ArrayList<ParticleData>();
131 protected ShipAPI target;
132 protected Vector2f offset;
133 protected int ticks = 0;
135 protected FaderUtil fader = new FaderUtil(1f, 0.5f, 0.5f);
136
138 this.proj = proj;
139 this.target = target;
140 this.offset = offset;
141
142 interval = new IntervalUtil(0.8f, 1f);
144 }
145
146 public float getRenderRadius() {
147 return 500f;
148 }
149
150
151 protected EnumSet<CombatEngineLayers> layers = EnumSet.of(CombatEngineLayers.BELOW_INDICATORS_LAYER);
152 @Override
153 public EnumSet<CombatEngineLayers> getActiveLayers() {
154 return layers;
155 }
156
158 super.init(entity);
159 }
160
161 public void advance(float amount) {
162 if (Global.getCombatEngine().isPaused()) return;
163
164 Vector2f loc = new Vector2f(offset);
166 Vector2f.add(target.getLocation(), loc, loc);
167 entity.getLocation().set(loc);
168
169 List<ParticleData> remove = new ArrayList<ParticleData>();
170 for (ParticleData p : particles) {
171 p.advance(amount);
172 if (p.elapsed >= p.maxDur) {
173 remove.add(p);
174 }
175 }
176 particles.removeAll(remove);
177
178 float volume = 1f;
180 fader.fadeOut();
181 fader.advance(amount);
182 volume = fader.getBrightness();
183 }
185
186
187 interval.advance(amount);
188 if (interval.intervalElapsed() && ticks < getNumTicks()) {
189 dealDamage();
190 ticks++;
191 }
192 }
193
194 protected String getSoundLoopId() {
195 return "disintegrator_loop";
196 }
197
198 protected int getNumParticlesPerTick() {
199 return 3;
200 }
201
202 protected void addParticle() {
203 ParticleData p = new ParticleData(30f, 3f + (float) Math.random() * 2f, 2f);
204 particles.add(p);
205 p.offset = Misc.getPointWithinRadius(p.offset, 20f);
206 }
207
208 protected void damageDealt(Vector2f loc, float hullDamage, float armorDamage) {
209
210 }
211
212 protected void dealDamage() {
214
215 int num = getNumParticlesPerTick();
216 for (int i = 0; i < num; i++) {
217 addParticle();
218 }
219
220
221 Vector2f point = new Vector2f(entity.getLocation());
222
223 // maximum armor in a cell is 1/15th of the ship's stated armor rating
224
226 int[] cell = grid.getCellAtLocation(point);
227 if (cell == null) return;
228
229 int gridWidth = grid.getGrid().length;
230 int gridHeight = grid.getGrid()[0].length;
231
232 float damageTypeMult = getDamageTypeMult(proj.getSource(), target);
233
234 float damagePerTick = (float) getTotalDamage() / (float) getNumTicks();
235 float damageDealt = 0f;
236 float hullDamage = 0f;
237 for (int i = -2; i <= 2; i++) {
238 for (int j = -2; j <= 2; j++) {
239 if ((i == 2 || i == -2) && (j == 2 || j == -2)) continue; // skip corners
240
241 int cx = cell[0] + i;
242 int cy = cell[1] + j;
243
244 if (cx < 0 || cx >= gridWidth || cy < 0 || cy >= gridHeight) continue;
245
246 float damMult = 1/30f;
247 if (i == 0 && j == 0) {
248 damMult = 1/15f;
249 } else if (i <= 1 && i >= -1 && j <= 1 && j >= -1) { // S hits
250 damMult = 1/15f;
251 } else { // T hits
252 damMult = 1/30f;
253 }
254
255 float armorInCell = grid.getArmorValue(cx, cy);
256 float damage = damagePerTick * damMult * damageTypeMult;
257 if (damage > armorInCell && canDamageHull()) {
258 hullDamage += damage - armorInCell;
259 }
260 damage = Math.min(damage, armorInCell);
261 if (damage <= 0) continue;
262
263 target.getArmorGrid().setArmorValue(cx, cy, Math.max(0, armorInCell - damage));
264 damageDealt += damage;
265 }
266 }
267
268 if (damageDealt > 0) {
271 }
273 }
274
275 if (hullDamage > 1f) {
276 float showHullDamage = Math.min(hullDamage, target.getHitpoints());
277 if (showHullDamage >= 0) {
278 target.setHitpoints(target.getHitpoints() - hullDamage);
279 if (target.getHitpoints() <= 0f && !target.isHulk()) {
280 target.setSpawnDebris(false);
281 engine.applyDamage(target, point, 100f, DamageType.ENERGY, 0f, true, false, proj.getSource(), false);
282 }
284 Vector2f p2 = new Vector2f(point);
285 p2.y += 20f;
287 }
288// String key = "wfewfewf";
289// Float total = (Float) engine.getCustomData().get(key);
290// if (total == null) total = 0f;
291// total += hullDamage;
292// engine.getCustomData().put(key, total);
293// System.out.println("Total hull damage dealt: " + total);
294 }
295 }
296
297 damageDealt(point, hullDamage, damageDealt);
298
299 }
300
301 public boolean isExpired() {
302 return particles.isEmpty() &&
304 }
305
307 float x = entity.getLocation().x;
308 float y = entity.getLocation().y;
309
310 //Color color = new Color(100,150,255,35);
311 float b = viewport.getAlphaMult();
312
313 GL14.glBlendEquation(GL14.GL_FUNC_REVERSE_SUBTRACT);
314
315 for (ParticleData p : particles) {
316 //float size = proj.getProjectileSpec().getWidth() * 0.6f;
317 float size = p.baseSize * p.scale;
318
319 Vector2f loc = new Vector2f(x + p.offset.x, y + p.offset.y);
320
321 float alphaMult = 1f;
322
323 p.sprite.setAngle(p.angle);
324 p.sprite.setSize(size, size);
325 p.sprite.setAlphaMult(b * alphaMult * p.fader.getBrightness());
326 p.sprite.setColor(p.color);
327 p.sprite.renderAtCenter(loc.x, loc.y);
328 }
329
330 GL14.glBlendEquation(GL14.GL_FUNC_ADD);
331 }
332
333
334 public static float getDamageTypeMult(ShipAPI source, ShipAPI target) {
335 if (source == null || target == null) return 1f;
336
338 switch (target.getHullSize()) {
339 case CAPITAL_SHIP:
340 damageTypeMult *= source.getMutableStats().getDamageToCapital().getModifiedValue();
341 break;
342 case CRUISER:
343 damageTypeMult *= source.getMutableStats().getDamageToCruisers().getModifiedValue();
344 break;
345 case DESTROYER:
346 damageTypeMult *= source.getMutableStats().getDamageToDestroyers().getModifiedValue();
347 break;
348 case FRIGATE:
349 damageTypeMult *= source.getMutableStats().getDamageToFrigates().getModifiedValue();
350 break;
351 case FIGHTER:
352 damageTypeMult *= source.getMutableStats().getDamageToFighters().getModifiedValue();
353 break;
354 }
355 return damageTypeMult;
356 }
357
358 public Vector2f getOffset() {
359 return offset;
360 }
361
362 public void setOffset(Vector2f offset) {
363 this.offset = offset;
364 }
365
366}
367
368
369
370
static SettingsAPI getSettings()
Definition Global.java:57
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:49
static CombatEngineAPI getCombatEngine()
Definition Global.java:69
DisintegratorEffect(DamagingProjectileAPI proj, ShipAPI target, Vector2f offset)
static float getDamageTypeMult(ShipAPI source, ShipAPI target)
void render(CombatEngineLayers layer, ViewportAPI viewport)
void damageDealt(Vector2f loc, float hullDamage, float armorDamage)
void onHit(DamagingProjectileAPI projectile, CombatEntityAPI target, Vector2f point, boolean shieldHit, ApplyDamageResultAPI damageResult, CombatEngineAPI engine)
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
Definition Misc.java:1196
static boolean shouldShowDamageFloaty(ShipAPI source, ShipAPI target)
Definition Misc.java:5955
static Color FLOATY_ARMOR_DAMAGE_COLOR
Definition Misc.java:214
static Vector2f rotateAroundOrigin(Vector2f v, float angle)
Definition Misc.java:1205
static Color FLOATY_HULL_DAMAGE_COLOR
Definition Misc.java:216
static Vector2f getPointWithinRadius(Vector2f from, float r)
Definition Misc.java:711
SpriteAPI getSprite(String filename)
void playLoop(String id, Object playingEntity, float pitch, float volume, Vector2f loc, Vector2f vel)
void setArmorValue(int cellX, int cellY, float value)
float getArmorValue(int cellX, int cellY)
CombatEntityAPI addLayeredRenderingPlugin(CombatLayeredRenderingPlugin plugin)
void applyDamage(CombatEntityAPI entity, Vector2f point, float damageAmount, DamageType damageType, float empAmount, boolean bypassShields, boolean dealsSoftFlux, Object source, boolean playSound)
void addFloatingDamageText(Vector2f loc, float damage, Color color, CombatEntityAPI attachedTo, CombatEntityAPI damageSource)
boolean isEntityInPlay(CombatEntityAPI entity)
void setSpawnDebris(boolean spawnDebris)
MutableShipStatsAPI getMutableStats()