Starsector API
Loading...
Searching...
No Matches
AbyssalLightEntityPlugin.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign;
2
3import java.awt.Color;
4
5import org.lwjgl.util.vector.Vector2f;
6
7import com.fs.starfarer.api.EveryFrameScript;
8import com.fs.starfarer.api.Global;
9import com.fs.starfarer.api.SoundAPI;
10import com.fs.starfarer.api.campaign.CampaignEngineLayers;
11import com.fs.starfarer.api.campaign.CampaignFleetAPI;
12import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI;
13import com.fs.starfarer.api.campaign.CustomEntitySpecAPI;
14import com.fs.starfarer.api.campaign.SectorEntityToken;
15import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel;
16import com.fs.starfarer.api.combat.ViewportAPI;
17import com.fs.starfarer.api.graphics.SpriteAPI;
18import com.fs.starfarer.api.impl.campaign.abilities.InterdictionPulseAbility;
19import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
20import com.fs.starfarer.api.impl.campaign.ids.Tags;
21import com.fs.starfarer.api.impl.campaign.intel.events.ht.HTPoints;
22import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin;
23import com.fs.starfarer.api.util.FaderUtil;
24import com.fs.starfarer.api.util.FlickerUtilV2;
25import com.fs.starfarer.api.util.Misc;
26
28
29 public static enum DespawnType {
30 FADE_OUT,
31 EXPAND,
32 }
33
34 public static float MIN_DURATION = 20f;
35 public static float MAX_DURATION = 30f;
36
37 public static float MIN_SIZE = 600f;
38 public static float MAX_SIZE = 1200f;
39
40 public static float DESPAWN_POOF_THRESHOLD = 0.7f;
41
42 public static float GLOW_FREQUENCY = 0.2f; // on/off cycles per second
43
44 public static float PLAYER_PROXIMITY_MIN_BRIGHTNESS_AT = 2000f;
45 public static float PLAYER_PROXIMITY_MAX_BRIGHTNESS_AT = 300f;
46 public static float PLAYER_PROXIMITY_MIN_BRIGHTNESS = 0.25f;
47
48
49 public static class AbyssalLightSoundStopper implements EveryFrameScript {
50 protected transient SoundAPI sound = null;
51 protected float elapsed = 0f;
52 public AbyssalLightSoundStopper(SoundAPI sound) {
53 this.sound = sound;
54 }
55 public boolean isDone() {
56 return sound == null;
57 }
58 public boolean runWhilePaused() {
59 return true;
60 }
61 public void advance(float amount) {
62 elapsed += amount;
63 if (sound == null) return;
64 if (!sound.isPlaying() && elapsed > 1f) {
65 sound = null;
66 return;
67 }
68
69 if (Global.getSector().isPaused() && sound != null) {
70 sound.stop();
71 sound = null;
72 }
73 }
74 }
75 public static class AbyssalLightParams {
76 public Color color = new Color(200,200,255,255);
77 public float frequencyMultMin = 0.5f;
78 public float frequencyMultMax = 1.5f;
79 public float frequencyChangeMult = 1f;
80 public float size;
81 public float detectedRange;
82 public float bonusMult;
83 public float durationDays;
84 public int pointsOverride = 0;
85
86 public AbyssalLightParams() {
87 this(MIN_SIZE, MAX_SIZE);
88 }
89 public AbyssalLightParams(float minSize, float maxSize) {
90 frequencyMultMin = 0.5f;
91 frequencyMultMax = 1.5f;
92
93 float sizeRange = maxSize - minSize;
94 float avgSize = MIN_SIZE + (MAX_SIZE - MIN_SIZE) * 0.5f;
95
96
97 size = minSize + (float) Math.random() * sizeRange;
98 detectedRange = (size * 3f) / HyperspaceTerrainPlugin.ABYSS_SENSOR_RANGE_MULT;
99
100 bonusMult = size / avgSize;
101
102 durationDays = MIN_DURATION + (MAX_DURATION - MIN_DURATION) * (float) Math.random();
103 }
104
105 public int getTopographyPoints() {
106 if (pointsOverride > 0) return pointsOverride;
107
108 return Math.round(HTPoints.ABYSSAL_LIGHT_MIN +
109 (HTPoints.ABYSSAL_LIGHT_AVG - HTPoints.ABYSSAL_LIGHT_MIN) * bonusMult);
110 }
111 }
112
113
114 transient private SpriteAPI glow;
115
116
117 protected float phase = 0f;
118 protected float frequencyMult = 1f;
119 protected FlickerUtilV2 flicker = new FlickerUtilV2();
120 protected FaderUtil fader = new FaderUtil(0f, 0.5f, 0.5f);
121 protected AbyssalLightParams params;
122 protected float untilFrequencyChange = 0f;
123 protected float untilSoundPlayed = 0f;
124 protected float flickerDur = 0f;
125 protected DespawnType despawnType = null;
126 protected boolean playedDespawnSound = false;
127
128 public void init(SectorEntityToken entity, Object pluginParams) {
129 super.init(entity, pluginParams);
130 params = (AbyssalLightParams) pluginParams;
131
132 float radiusMult = params.bonusMult;
133 if (radiusMult > 1f) {
134 radiusMult = 1f + (radiusMult - 1f) * 0.33f;
135 } else if (radiusMult < 1f) {
136 radiusMult = 1f - (1f - radiusMult) * 0.33f;
137 }
138 ((CustomCampaignEntityAPI) entity).setRadius(entity.getRadius() * radiusMult);
139 entity.setSensorProfile(1f);
140 entity.setDiscoverable(false);
141 //entity.setDiscoveryXP(spec.getDiscoveryXP());
142
143 entity.getDetectedRangeMod().modifyFlat("gen", params.detectedRange);
144 entity.setExtendedDetectedAtRange(2000f);
145 entity.setDetectionRangeDetailsOverrideMult(0.5f);
146 entity.getMemoryWithoutUpdate().set(MemFlags.EXTRA_SENSOR_INDICATORS, 3);
147
148 updateFrequency(0f);
150 readResolve();
151 }
152
153 public boolean isDespawning() {
154 return despawnType != null || entity.hasTag(Tags.FADING_OUT_AND_EXPIRING);
155 }
156
157 public void despawn(DespawnType type) {
158 if (isDespawning()) return;
159
160 float dur = 1f;
161 if (type == DespawnType.EXPAND) dur = 2f;
162 Misc.fadeAndExpire(entity, dur);
163 despawnType = type;
164
165 if (type == DespawnType.EXPAND && entity.isInCurrentLocation()) {
166 VisibilityLevel level = entity.getVisibilityLevelToPlayerFleet();
167 if (level == VisibilityLevel.COMPOSITION_DETAILS || level == VisibilityLevel.COMPOSITION_AND_FACTION_DETAILS) {
168 Global.getSoundPlayer().playSound("abyssal_light_expand_despawn_windup", 1f, 1f, entity.getLocation(), Misc.ZERO);
169 }
170 }
171 }
172
173 public void updateSoundDelayAndPlaySound(float amount) {
174 untilSoundPlayed -= amount;
175 if (untilSoundPlayed <= 0f) {
176 //untilSoundPlayed = 0.5f + (float) Math.random() * 20f;
177 untilSoundPlayed = 5f + (float) Math.random() * 30f;
178
179 // don't play sound when called from the constructor with amount == 0f
180 if (amount > 0 && entity.isInCurrentLocation()) {
181 VisibilityLevel level = entity.getVisibilityLevelToPlayerFleet();
182 if (level == VisibilityLevel.COMPOSITION_DETAILS || level == VisibilityLevel.COMPOSITION_AND_FACTION_DETAILS) {
183 float volume = 1f;
184 if (params.bonusMult < 1f) {
185 volume = 1f - (1f - params.bonusMult) * 0.6f;
186 }
187 if (volume > 1f) volume = 1f;
188 if (volume < 0f) volume = 0f;
189 SoundAPI sound = Global.getSoundPlayer().playSound("abyssal_light_random_sound", 1f, volume, entity.getLocation(), Misc.ZERO);
190 Global.getSector().addScript(new AbyssalLightSoundStopper(sound));
191 //flickerDur = 3f + 2f * (float) Math.random();
192 flickerDur = 0.5f + 0.5f * (float) Math.random();
193 }
194 }
195 }
196 }
197 public void updateFrequency(float amount) {
198 untilFrequencyChange -= amount * params.frequencyChangeMult;
199 if (untilFrequencyChange <= 0f) {
200 untilFrequencyChange = 1f + (float) Math.random() * 3f;
201
202 frequencyMult = params.frequencyMultMin *
203 (float) Math.random() * (params.frequencyMultMax - params.frequencyMultMin);
204 }
205 }
206
207 Object readResolve() {
208 glow = Global.getSettings().getSprite("campaignEntities", "abyssal_light_glow");
209 return this;
210 }
211
212 public AbyssalLightParams getParams() {
213 return params;
214 }
215
216
217 public void advance(float amount) {
218 if (isDespawning()) {
219 if (!playedDespawnSound &&
220 (getDespawnProgress() > DESPAWN_POOF_THRESHOLD || despawnType == DespawnType.FADE_OUT)) {
221 playedDespawnSound = true;
222 if (entity.isInCurrentLocation()) {
223 VisibilityLevel level = entity.getVisibilityLevelToPlayerFleet();
224 if (level == VisibilityLevel.COMPOSITION_DETAILS || level == VisibilityLevel.COMPOSITION_AND_FACTION_DETAILS) {
225 String soundId = "abyssal_light_despawn_disrupted";
226 if (despawnType == DespawnType.FADE_OUT) {
227 soundId = "abyssal_light_despawn_expired";
228 }
229 Global.getSoundPlayer().playSound(soundId, 1f, 1f, entity.getLocation(), Misc.ZERO);
230 }
231 }
232 }
233
234 return;
235 }
236
237 float days = Misc.getDays(amount);
238 params.durationDays -= days;
239 if (params.durationDays <= 0f || Misc.getAbyssalDepth(entity) < 1f) {
240 despawn(DespawnType.FADE_OUT);
241 return;
242 }
243
244 updateFrequency(amount);
246
247 phase += amount * GLOW_FREQUENCY * frequencyMult;
248 while (phase > 1) phase --;
249
250 if (flickerDur > 0) {
251 flickerDur -= amount;
252 if (flickerDur < 0) flickerDur = 0;
253 }
254
255 flicker.advance(amount * 10f);
256 fader.advance(amount);
257
258 if (Global.getSector().getMemoryWithoutUpdate().getBoolean(MemFlags.GLOBAL_INTERDICTION_PULSE_JUST_USED_IN_CURRENT_LOCATION)) {
259 if (entity.getContainingLocation() != null) {
260 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) {
261 float range = InterdictionPulseAbility.getRange(fleet);
262 float dist = Misc.getDistance(fleet.getLocation(), entity.getLocation());
263 if (dist > range) continue;
264
265
266 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.JUST_DID_INTERDICTION_PULSE)) {
268
269 float brightness = getProximityBasedBrightnessFactor(fleet, entity.getLocation());
270 bonus.addBurnBonus(params.bonusMult * brightness);
271
272 if (fleet.isPlayerFleet()) {
273 bonus.addTopographyPoints(params.getTopographyPoints());
274 }
275
276 despawn(DespawnType.EXPAND);
277 }
278 }
279 }
280 if (isDespawning()) return;
281 }
282
283 if (Global.getSector().getMemoryWithoutUpdate().getBoolean(MemFlags.GLOBAL_SENSOR_BURST_JUST_USED_IN_CURRENT_LOCATION)) {
284 if (entity.getContainingLocation() != null) {
285 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) {
286 float range = 500f + fleet.getRadius() + entity.getRadius();
287 float dist = Misc.getDistance(fleet.getLocation(), entity.getLocation());
288 if (dist > range) continue;
289
290
291 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.JUST_DID_SENSOR_BURST)) {
293
294 float brightness = getProximityBasedBrightnessFactor(fleet, entity.getLocation());
295 bonus.addSensorBonus(params.bonusMult * brightness);
296
297 if (fleet.isPlayerFleet()) {
298 bonus.addTopographyPoints(params.getTopographyPoints());
299 }
300
301 despawn(DespawnType.EXPAND);
302 }
303 }
304 }
305 if (isDespawning()) return;
306 }
307 }
308
309 public float getFlickerBasedMult() {
310 if (flickerDur <= 0f) return 1f;
311
312 float mult = 1f;
313 if (flickerDur < 1f) mult = flickerDur;
314
315 mult *= 0.25f;
316
317 float f = 1f - flicker.getBrightness() * mult;
318 return f;
319 }
320
321 public float getGlowAlpha() {
322 float glowAlpha = 0f;
323 if (phase < 0.5f) glowAlpha = phase * 2f;
324 if (phase >= 0.5f) glowAlpha = (1f - (phase - 0.5f) * 2f);
325 glowAlpha = 0.75f + glowAlpha * 0.25f;
326 //glowAlpha *= getFlickerBasedMult();
327
328 if (glowAlpha < 0) glowAlpha = 0;
329 if (glowAlpha > 1) glowAlpha = 1;
330 return glowAlpha;
331 }
332
333
334
335 public float getRenderRange() {
336 return entity.getRadius() + params.size * 0.75f;
337 }
338
339 public float getDespawnProgress() {
340 if (!isDespawning()) return 0f;
341 float f = entity.getSensorFaderBrightness();
342 return 1 - f;
343 }
344
345 public void render(CampaignEngineLayers layer, ViewportAPI viewport) {
346 float alphaMult = viewport.getAlphaMult();
347
348 if (!isDespawning() || despawnType == DespawnType.FADE_OUT) {
349 alphaMult *= entity.getSensorFaderBrightness();
350 }
351
352 if (alphaMult <= 0) return;
353
354 float f = getDespawnProgress();
355 if (despawnType == DespawnType.FADE_OUT) {
356 f = 0f;
357 }
358
359 if (f > DESPAWN_POOF_THRESHOLD) {
360 float fadeOut = (1f - f) / (1f - DESPAWN_POOF_THRESHOLD);
361 alphaMult *= fadeOut;
362 }
363
364 VisibilityLevel level = entity.getVisibilityLevelToPlayerFleet();
365 if (level == VisibilityLevel.COMPOSITION_DETAILS || level == VisibilityLevel.COMPOSITION_AND_FACTION_DETAILS) {
366 fader.fadeIn();
367 } else {
368 fader.fadeOut();
369 }
370
371 alphaMult *= fader.getBrightness();
372
374 alphaMult *= b;
375
376
377// if (Misc.getDistanceToPlayerLY(entity) > 0.1f) {
378// Misc.fadeAndExpire(entity);
379// return;
380// }
381// if (!Global.getSector().isPaused()) {
382// System.out.println("Alpha: " + alphaMult);
383// }
384
385 CustomEntitySpecAPI spec = entity.getCustomEntitySpec();
386 if (spec == null) return;
387
388 float w = spec.getSpriteWidth();
389 float h = spec.getSpriteHeight();
390
391 Vector2f loc = entity.getLocation();
392
393 float glowAlpha = getGlowAlpha();
394
395 glow.setColor(params.color);
396
397 w = params.size;
398 h = params.size;
399
400 float scale = 0.25f + alphaMult * 0.75f;
401 if (f > DESPAWN_POOF_THRESHOLD) {
402 scale *= 1.5f;
403 }
404
405 float fringeScale = 1f;
406 //fringeScale = 1.5f;
407
408 glow.setAdditiveBlend();
409
410 if (layer == CampaignEngineLayers.TERRAIN_8) {
411 //float flicker = getFlickerBasedMult();
412 glow.setAlphaMult(alphaMult * glowAlpha * 0.5f);
413 glow.setSize(w * scale * fringeScale, h * scale * fringeScale);
414
415 glow.renderAtCenter(loc.x, loc.y);
416 }
417
418 if (layer == CampaignEngineLayers.STATIONS) {
419 if (f > 0f) {
420 float extra = 1f + f * 1.33f;
421 if (f > DESPAWN_POOF_THRESHOLD) extra = 0f;
422 scale *= extra;
423 }
425 for (int i = 0; i < 5; i++) {
426 if (i != 0) flicker = 1f;
427
428 w *= 0.3f;
429 h *= 0.3f;
430 glow.setSize(w * scale, h * scale);
431 glow.setAlphaMult(alphaMult * glowAlpha * 0.67f * flicker);
432 glow.renderAtCenter(loc.x, loc.y);
433 }
434 }
435 }
436
437
438 public static float getPlayerProximityBasedBrightnessFactor(SectorEntityToken entity) {
440 }
441 public static float getPlayerProximityBasedBrightnessFactor(Vector2f loc) {
442 CampaignFleetAPI player = Global.getSector().getPlayerFleet();
443 if (player == null) {
445 }
446 return getProximityBasedBrightnessFactor(player, loc);
447 }
448
449 public static float getProximityBasedBrightnessFactor(CampaignFleetAPI from, Vector2f loc) {
450
451 float dist = Misc.getDistance(from.getLocation(), loc) - from.getRadius();
452
454 return 1f;
455 //return Math.max(PLAYER_PROXIMITY_MIN_BRIGHTNESS, dist / PLAYER_PROXIMITY_MAX_BRIGHTNESS_AT);
456 }
458
460 if (f < 0f) f = 0f;
461
463
464 return b;
465 }
466
467
468// @Override
469// public void createMapTooltip(TooltipMakerAPI tooltip, boolean expanded) {
470// String post = "";
471// Color color = entity.getFaction().getBaseUIColor();
472// Color postColor = color;
473// if (entity.getMemoryWithoutUpdate().getBoolean(RemnantSystemType.DESTROYED.getBeaconFlag())) {
474// post = " - Low";
475// postColor = Misc.getPositiveHighlightColor();
476// } else if (entity.getMemoryWithoutUpdate().getBoolean(RemnantSystemType.SUPPRESSED.getBeaconFlag())) {
477// post = " - Medium";
478// postColor = Misc.getHighlightColor();
479// } else if (entity.getMemoryWithoutUpdate().getBoolean(RemnantSystemType.RESURGENT.getBeaconFlag())) {
480// post = " - High";
481// postColor = Misc.getNegativeHighlightColor();
482// }
483//
484// tooltip.addPara(entity.getName() + post, 0f, color, postColor, post.replaceFirst(" - ", ""));
485// }
486//
487// @Override
488// public boolean hasCustomMapTooltip() {
489// return true;
490// }
491//
492// @Override
493// public void appendToCampaignTooltip(TooltipMakerAPI tooltip, VisibilityLevel level) {
494// if (level == VisibilityLevel.COMPOSITION_AND_FACTION_DETAILS ||
495// level == VisibilityLevel.COMPOSITION_DETAILS) {
496//
497// String post = "";
498// Color color = Misc.getTextColor();
499// Color postColor = color;
500// if (entity.getMemoryWithoutUpdate().getBoolean(RemnantSystemType.DESTROYED.getBeaconFlag())) {
501// post = "low";
502// postColor = Misc.getPositiveHighlightColor();
503// } else if (entity.getMemoryWithoutUpdate().getBoolean(RemnantSystemType.SUPPRESSED.getBeaconFlag())) {
504// post = "medium";
505// postColor = Misc.getHighlightColor();
506// } else if (entity.getMemoryWithoutUpdate().getBoolean(RemnantSystemType.RESURGENT.getBeaconFlag())) {
507// post = "high";
508// postColor = Misc.getNegativeHighlightColor();
509// }
510// if (!post.isEmpty()) {
511// tooltip.setParaFontDefault();
512// tooltip.addPara(BaseIntelPlugin.BULLET + "Danger level: " + post, 10f, color, postColor, post);
513// }
514// }
515//
516// }
517}
518
519
520
521
522
523
524
525
526
static SettingsAPI getSettings()
Definition Global.java:51
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:43
static SectorAPI getSector()
Definition Global.java:59
static AbyssalLightBonus get(CampaignFleetAPI fleet)
static float getPlayerProximityBasedBrightnessFactor(SectorEntityToken entity)
static float getProximityBasedBrightnessFactor(CampaignFleetAPI from, Vector2f loc)
void init(SectorEntityToken entity, Object pluginParams)
void render(CampaignEngineLayers layer, ViewportAPI viewport)
SpriteAPI getSprite(String filename)
SoundAPI playSound(String id, float pitch, float volume, Vector2f loc, Vector2f vel)