Starsector API
Loading...
Searching...
No Matches
SlipstreamManager.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.velfield;
2
3import java.util.ArrayList;
4import java.util.HashSet;
5import java.util.Iterator;
6import java.util.LinkedHashMap;
7import java.util.LinkedHashSet;
8import java.util.List;
9import java.util.Map;
10import java.util.Random;
11import java.util.Set;
12
13import org.lwjgl.util.vector.Vector2f;
14
15import com.fs.starfarer.api.EveryFrameScript;
16import com.fs.starfarer.api.Global;
17import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
18import com.fs.starfarer.api.campaign.JumpPointAPI;
19import com.fs.starfarer.api.campaign.LocationAPI;
20import com.fs.starfarer.api.campaign.NascentGravityWellAPI;
21import com.fs.starfarer.api.campaign.SectorEntityToken;
22import com.fs.starfarer.api.campaign.StarSystemAPI;
23import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
24import com.fs.starfarer.api.impl.campaign.DebugFlags;
25import com.fs.starfarer.api.impl.campaign.ids.Tags;
26import com.fs.starfarer.api.impl.campaign.ids.Terrain;
27import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceAbyssPlugin;
28import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin;
29import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamBuilder.StreamType;
30import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2.SlipstreamParams2;
31import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2.SlipstreamSegment;
32import com.fs.starfarer.api.impl.campaign.world.TTBlackSite;
33import com.fs.starfarer.api.util.CollisionGridUtil;
34import com.fs.starfarer.api.util.IntervalUtil;
35import com.fs.starfarer.api.util.Misc;
36import com.fs.starfarer.api.util.WeightedRandomPicker;
37
38public class SlipstreamManager implements EveryFrameScript {
39
40 public static int WIDTH = 21;
41 public static int HEIGHT = 11;
42 public static float MAP_WIDTH_PADDING = 8000;
43 public static float MAP_HEIGHT_PADDING = 5000;
61 public static Map<String, Float> STREAM_CONFIGS = new LinkedHashMap<String, Float>();
62
63 static {
65 }
66
67 public static void loadConfigs() {
68 // begin "finished"
70 "aD? B" +
71 "C? EA" +
72 " c " +
73 " " +
74 " " +
75 " X " +
76 " " +
77 " " +
78 " d " +
79 "A!E? C" +
80 "B! Db"
81 , 10f);
83 "Ba C D aB" +
84 " " +
85 " " +
86 " " +
87 " " +
88 " CXD " +
89 " e " +
90 " " +
91 " " +
92 " " +
93 "A!bE EbA"
94 , 10f);
96 "A! D? F? A" +
97 " " +
98 " " +
99 "a a" +
100 " " +
101 "C! DE X FG C" +
102 " " +
103 "b b" +
104 " " +
105 " " +
106 "B! E? G? B"
107 , 10f);
108 STREAM_CONFIGS.put(
109 "C! D! cA" +
110 " " +
111 " " +
112 " " +
113 "A? aa" +
114 " X c" +
115 "B? bb" +
116 " " +
117 " " +
118 "d C " +
119 "d DB"
120 , 10f);
121 STREAM_CONFIGS.put(
122 "B^! I^? H^? a G" +
123 " " +
124 " i h " +
125 " g" +
126 " A!| H^G^? " +
127 " C^<I X " +
128 " D^ E^?F^? F" +
129 "c AB " +
130 " " +
131 "b d " +
132 "C? D?e a E"
133 , 10f);
134 STREAM_CONFIGS.put(
135 " b a " +
136 "A|~+0 A" +
137 " " +
138 "B|~+0 B" +
139 " c a " +
140 " X " +
141 " " +
142 "C|!+0 d C" +
143 " b " +
144 "D|~+0 D" +
145 " d c "
146 , 10f);
147
148 // highly randomized and mirrored
149 STREAM_CONFIGS.put(
150 "A* B* G" +
151 " H* g " +
152 " h H " +
153 " b " +
154 " C* A G* " +
155 " X F" +
156 " c D " +
157 " B E* e " +
158 " d f " +
159 " " +
160 "D* C F* E"
161 , 5f);
162 String prev = (String) STREAM_CONFIGS.keySet().toArray()[STREAM_CONFIGS.size() - 1];
163 STREAM_CONFIGS.put(mirrorHorz(prev), 5f);
164 STREAM_CONFIGS.put(mirrorVert(prev), 5f);
165 STREAM_CONFIGS.put(mirrorHorz(mirrorVert(prev)), 5f);
166
167 // end "finished"
168
169
170 // maybe?
171// STREAM_CONFIGS.put(
172// "A|!~+0C D FE A" +
173// "c d B" +
174// " " +
175// " " +
176// " " +
177// " f X e " +
178// " " +
179// " " +
180// " " +
181// "B|!<-5D^ " +
182// " C^ F^E<^ bb"
183// , 10f);
184// STREAM_CONFIGS.put( // also maybe, very similar to another one though
185// "A C D A" +
186// " c d " +
187// " " +
188// " " +
189// " e " +
190// " X " +
191// " b " +
192// "E a E" +
193// " " +
194// " " +
195// "B C D B"
196// , 10f);
197
198 // blank
199// STREAM_CONFIGS.put(
200// " " +
201// " " +
202// " " +
203// " " +
204// " " +
205// " X " +
206// " " +
207// " " +
208// " " +
209// " " +
210// " "
211// , 10f);
212
213 }
214
215 public static void mirrorPrevVert(float weight) {
216 String prev = (String) STREAM_CONFIGS.keySet().toArray()[STREAM_CONFIGS.size() - 1];
217 STREAM_CONFIGS.put(mirrorVert(prev), weight);
218 }
219 public static String mirrorVert(String in) {
220 String out = "";
221 for (int j = 0; j < HEIGHT; j++) {
222 out = in.substring(j * WIDTH, (j + 1) * WIDTH) + out;
223 }
224 return out;
225 }
226 public static void mirrorPrevHorz(float weight) {
227 String prev = (String) STREAM_CONFIGS.keySet().toArray()[STREAM_CONFIGS.size() - 1];
228 STREAM_CONFIGS.put(mirrorHorz(prev), weight);
229 }
230 public static String mirrorHorz(String in) {
231 String out = "";
232 for (int j = 0; j < HEIGHT; j++) {
233 out = out + new StringBuilder(in.substring(j * WIDTH, (j + 1) * WIDTH)).reverse();
234 }
235 return out;
236 }
237
238 public static void validateConfigs() {
239 // make sure they all parse
240 for (String key : STREAM_CONFIGS.keySet()) {
241 if (key.length() != WIDTH * HEIGHT) {
242 throw new RuntimeException("Length of slipstream config not WIDTHxHEIGHT [" + key + "]");
243 }
244 try {
245 new StreamConfig(key, null);
246 } catch (Throwable t) {
247 throw new RuntimeException("Error parsing slipstream config [" + key + "]", t);
248 }
249 }
250
251 }
252
253 public static class StreamData {
254 public String id;
255 public int p0x = -1;
256 public int p0y = -1;
257 public int p1x = -1;
258 public int p1y = -1;
259 public int controlX = -1;
260 public int controlY = -1;
261 public int control2X = -1;
262 public int control2Y = -1;
263 public int burnMod = 0;
264 public boolean reverse = false;
265 public StreamType type = StreamType.NORMAL;
266 public boolean wasUsed = false;
267 public boolean straight = false;
268 public boolean priority = false;
269 public boolean onlyKeepLongestSegment = false;
270 public boolean randomize = false;
271 public boolean minorRandomize = false;
272
273 public StreamData(String id) {
274 this.id = id;
275 }
276 public Vector2f generateP0(Random random) {
277 if (p0x < 0) return null;
278 return generate(p0x, p0y, random);
279 }
280 public Vector2f generateP1(Random random) {
281 if (p1x < 0) return null;
282 return generate(p1x, p1y, random);
283 }
284 public Vector2f generateControl(Random random) {
285 if (controlX < 0) return null;
286 return generate(controlX, controlY, random);
287 }
288 public Vector2f generateControl2(Random random) {
289 if (control2X < 0) return null;
290 return generate(control2X, control2Y, random);
291 }
292 public Vector2f generate(int cellX, int cellY, Random random) {
293 float sw = Global.getSettings().getFloat("sectorWidth") - MAP_WIDTH_PADDING;
294 float sh = Global.getSettings().getFloat("sectorHeight") - MAP_HEIGHT_PADDING;
295 float cellWidth = sw / WIDTH;
296 float cellHeight = sh / HEIGHT;
297 Vector2f p = new Vector2f();
298// if (cellX == 20) {
299// System.out.println("efwefwef");
300// }
301 float minX = -sw/2f + cellWidth * cellX;
302 float maxX = -sw/2f + cellWidth * (cellX + 1);
303 float minY = -sh/2f + cellHeight * cellY;
304 float maxY = -sh/2f + cellHeight * (cellY + 1);
305
306 p.x = minX + (maxX - minX) * random.nextFloat();
307 p.y = minY + (maxY - minY) * random.nextFloat();
308// p.x = minX + (maxX - minX) * 0f;
309// p.y = minY + (maxY - minY) * 0f;
310// p.x = minX + (maxX - minX) * 1f;
311// p.y = minY + (maxY - minY) * 1f;
312
313 return p;
314 }
315 }
316
317 public static class StreamConfig {
318
319 public List<StreamData> streams = new ArrayList<StreamData>();
320 public String data;
321 public StreamConfig(String data, Random random) {
322 this.data = data;
323 Set<String> ids = new LinkedHashSet<String>();
324 for (int i = 0; i < data.length(); i++) {
325 char c = data.charAt(i);
326 if (c == 'X') continue;
327 if (Character.isUpperCase(c)) {
328 ids.add("" + c);
329 }
330 }
331
332 for (String id : ids) {
333 StreamData curr = new StreamData(id);
334 for (int i = 0; i < data.length(); i++) {
335 char c = data.charAt(i);
336 if (c == 'X') continue;
337
338 int cellX = i % WIDTH;
339 int cellY = HEIGHT - i / WIDTH - 1;
340 if (id.equals("" + c)) {
341 if (curr.p0x < 0) {
342 curr.p0x = cellX;
343 curr.p0y = cellY;
344 } else if (curr.p1x < 0) {
345 curr.p1x = cellX;
346 curr.p1y = cellY;
347 }
348 } else if (id.toLowerCase().equals("" + c)) {
349 if (curr.controlX < 0) {
350 curr.controlX = cellX;
351 curr.controlY = cellY;
352 } else {
353 curr.control2X = cellX;
354 curr.control2Y = cellY;
355 }
356 }
357
358 if (id.equals("" + c)) {
359 for (int j = i + 1; j < data.length() && j < i + 10; j++) {
360 char c2 = data.charAt(j);
361 if (c2 == ' ' || Character.isAlphabetic(c2)) break;
362 if (c2 == '<') {
363 curr.reverse = true;
364 } else if (c2 == '~') {
365 curr.type = StreamType.NARROW;
366 } else if (c2 == '=') {
367 curr.type = StreamType.WIDE;
368 } else if (c2 == '-') {
369 int burnMod = data.charAt(j + 1) - '0';
370 if (burnMod == 0) burnMod = 10;
371 curr.burnMod = -1 * burnMod;
372 } else if (c2 == '+') {
373 int burnMod = data.charAt(j + 1) - '0';
374 if (burnMod == 0) burnMod = 10;
375 curr.burnMod = burnMod;
376 } else if (c2 == '|') {
377 curr.straight = true;
378 } else if (c2 == '!') {
379 curr.priority = true;
380 } else if (c2 == '^') {
381 curr.onlyKeepLongestSegment = true;
382 } else if (c2 == '*') {
383 curr.randomize = true;
384 } else if (c2 == '?') {
385 curr.minorRandomize = true;
386 }
387 }
388 }
389 }
390 if (curr.p0x >= 0 || curr.p1x >= 0) {
391 if ((curr.randomize || curr.minorRandomize) && random != null) {
392 if (!curr.reverse && !curr.minorRandomize) {
393 curr.reverse = random.nextFloat() < 0.5f;
394 }
395 if (!curr.straight) {
396 curr.straight = random.nextFloat() < 0.25f;
397 }
398 if (curr.burnMod == 0) {
399 //curr.burnMod = (random.nextBoolean() ? 1 : -1) * random.nextInt(6);
400 if (curr.minorRandomize) {
401 curr.burnMod = random.nextInt(6);
402 } else {
403 curr.burnMod = random.nextInt(11);
404 }
405 }
406 if (curr.type == StreamType.NORMAL) {
407 float r = random.nextFloat();
408 if (r < 0.2f) {
409 curr.type = StreamType.NARROW;
410 } else if (r < 0.4f) {
411 curr.type = StreamType.WIDE;
412 }
413 }
414 }
415 streams.add(curr);
416 }
417 }
418 }
419 }
420
421
422 public static class AddedStream {
423 public CampaignTerrainAPI terrain;
424 public SlipstreamTerrainPlugin2 plugin;
425 public Vector2f from;
426 public Vector2f to;
427 public Vector2f control;
428 public long timestamp;
429 public AddedStream(SlipstreamTerrainPlugin2 plugin) {
430 this.plugin = plugin;
431 terrain = (CampaignTerrainAPI) plugin.getEntity();
432 from = new Vector2f(plugin.getSegments().get(0).loc);
433 to = new Vector2f(plugin.getSegments().get(plugin.getSegments().size() - 1).loc);
434 timestamp = Global.getSector().getClock().getTimestamp();
435 }
436 }
437
438
439 protected transient CollisionGridUtil grid;
440
441 protected IntervalUtil interval = new IntervalUtil(1f, 2f);
442 protected Random random = new Random();
443 protected int prevMonth = -1;
444 protected int desiredNumStreams = 0;
445 protected List<AddedStream> active = new ArrayList<SlipstreamManager.AddedStream>();
446 protected StreamConfig config;
447 protected String prevConfig;
448
449 protected Object readResolve() {
450 if (active == null) {
451 active = new ArrayList<SlipstreamManager.AddedStream>();
452 }
453 return this;
454 }
455
456
457 public void advance(float amount) {
458 //if (true) return;
460 random = Misc.random;
461 }
462
463// int total = 0;
464// for (AddedStream curr : active) {
465// total += curr.plugin.getSegments().size();
466// }
467// System.out.println("TOTAL SEGMENTS: " + total + ", streams: " + active.size());
468
469 float days = Global.getSector().getClock().convertToDays(amount);
471 days *= 100f;
472 }
473 interval.advance(days);
474 //DebugFlags.SLIPSTREAM_DEBUG = true;
475 if (interval.intervalElapsed()) {
476 Iterator<AddedStream> iter = active.iterator();
477 while (iter.hasNext()) {
478 AddedStream curr = iter.next();
479 if (!curr.terrain.isAlive()) {
480 iter.remove();
481 }
482 }
483
484 int month = Global.getSector().getClock().getMonth();
485 //month = 6;
486 if (month == 6 || month == 12) {
487 for (AddedStream curr : active) {
488 if (curr.plugin.isDespawning()) continue;
489 float despawnDelay = 0f + random.nextFloat() * 20f;
490 float timeMinusDelay = 27f - despawnDelay;
491 float despawnDays = timeMinusDelay * 0.5f + random.nextFloat() * timeMinusDelay * 0.5f;
492 curr.plugin.despawn(despawnDelay, despawnDays, random);
493 }
494 if (config != null) {
495 prevConfig = config.data;
496 }
497 config = null;
498 } else if (month != 6 && month != 12) {
499 if (config == null) {
501 STREAM_CONFIGS.clear();
502 loadConfigs();
503 }
504
505 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(random);
506 for (String key : STREAM_CONFIGS.keySet()) {
507 if (prevConfig != null && prevConfig.equals(key) && STREAM_CONFIGS.size() > 1) {
508 continue;
509 }
510 picker.add(key, STREAM_CONFIGS.get(key));
511 }
512 if (picker.isEmpty() && prevConfig != null) {
513 picker.add(prevConfig, 1f);
514 }
515 ListenerUtil.updateSlipstreamConfig(prevConfig, picker, this);
516 String data = picker.pick();
517 if (data != null) {
518 config = new StreamConfig(data, random);
519 }
520 }
521 addStream(month);
522 }
523
524
525 prevMonth = month;
526 }
527 grid = null;
528 }
529
530
531 public void addStream(int month) {
532 if (config == null) return;
533
534 //random = new Random();
535// long seed = 23895464576452L + 4384357483229348234L + 4343253L;
536// seed = 1181783497276652981L ^ seed;
537// Random random = new Random(seed);
538
539 WeightedRandomPicker<StreamData> picker = new WeightedRandomPicker<StreamData>(random);
540 for (StreamData data : config.streams) {
541 if (data.wasUsed) continue;
542 if (!data.priority) continue;
543 picker.add(data);
544 }
545 if (picker.isEmpty()) {
546 // add non-priority if all priority ones are already used
547 for (StreamData data : config.streams) {
548 if (data.wasUsed) continue;
549 picker.add(data);
550 }
551 }
552
553 StreamData data = picker.pick();
554 if (data == null) return;
555
556 SlipstreamParams2 params = new SlipstreamParams2();
557 params.burnLevel = 30 + data.burnMod;
558 params.minSpeed = Misc.getSpeedForBurnLevel(params.burnLevel - 5);
559 params.maxSpeed = Misc.getSpeedForBurnLevel(params.burnLevel + 5);
560 params.lineLengthFractionOfSpeed = 0.25f * Math.max(0.25f, Math.min(1f, 30f / (float) params.burnLevel));
561
562
563 Vector2f from = data.generateP0(random);
564 Vector2f to = data.generateP1(random);
565 Vector2f control = data.generateControl(random);
566 Vector2f control2 = data.generateControl2(random);
567 if (from == null || to == null) return;
568
569 // default direction is east in first half of the cycle, west in the second half
570 // months 6 and 12 don't really matter since the slipstreams despawn during those
571 if (month == 12 || month < 6) {
572 //if (!(month == 12 || month < 6)) {
573 if ((!data.reverse && from.x > to.x) || (data.reverse && from.x < to.x)) {
574 Vector2f temp = to;
575 to = from;
576 from = temp;
577 }
578 } else {
579 if ((!data.reverse && from.x < to.x) || (data.reverse && from.x > to.x)) {
580 Vector2f temp = to;
581 to = from;
582 from = temp;
583 }
584 }
585
586
587 LocationAPI hyperspace = Global.getSector().getHyperspace();
588 CampaignTerrainAPI slipstream = (CampaignTerrainAPI) hyperspace.addTerrain(Terrain.SLIPSTREAM, params);
589
590 slipstream.setLocation(from.x, from.y);
591 SlipstreamTerrainPlugin2 plugin = (SlipstreamTerrainPlugin2) slipstream.getPlugin();
592 SlipstreamBuilder builder = new SlipstreamBuilder(slipstream.getLocation(), plugin, data.type, random);
593
594 if (data.straight) {
595 float mult = 0.25f;
596 builder.setMaxAngleVariance(builder.getMaxAngleVariance() * mult);
598 }
599
600 if (control2 != null) {
601 float dist1 = Misc.getDistance(from, control);
602 float dist2 = Misc.getDistance(from, control2);
603 if (dist2 < dist1) {
604 Vector2f temp = control2;
605 control2 = control;
606 control = temp;
607 }
608 builder.buildToDestination(control, control2, to);
609 } else if (control != null) {
610 builder.buildToDestination(control, to);
611 } else {
612 builder.buildToDestination(to);
613 }
614
615 checkIntersectionsAndFadeSections(plugin, data.onlyKeepLongestSegment);
616
617 if (plugin.getSegments().size() < 3) {
618 hyperspace.removeEntity(slipstream);
619 return;
620 }
621
622 float spawnDays = 1f + 2f * random.nextFloat();
624 spawnDays = 0f;
625 }
626 plugin.spawn(spawnDays, random);
627
629
630 AddedStream added = new AddedStream(plugin);
631 active.add(added);
632 data.wasUsed = true;
633 }
634
635 public void checkIntersectionsAndFadeSections(SlipstreamTerrainPlugin2 plugin, boolean onlyKeepLongestBetweenStreams) {
636 updateGrid();
637
638 plugin.recomputeIfNeeded();
639
640 List<SlipstreamSegment> segments = plugin.getSegments();
641
642 Set<SlipstreamSegment> otherStreamCuts = new HashSet<SlipstreamSegment>();
643
644 for (SlipstreamSegment curr : segments) {
645
646 Iterator<Object> iter = grid.getCheckIterator(curr.loc, curr.width / 2f, curr.width / 2f);
647 while (iter.hasNext()) {
648 Object obj = iter.next();
649 if (obj instanceof JumpPointAPI) {
650 JumpPointAPI jp = (JumpPointAPI) obj;
651 Vector2f loc = jp.getLocation();
652 float radius = jp.getRadius();
653 if (jp.getOrbitFocus() != null) {
654 loc = jp.getOrbitFocus().getLocation();
655 radius = Misc.getDistance(jp.getOrbitFocus(), jp) + jp.getRadius();
656 }
657
658 Vector2f diff = Vector2f.sub(loc, curr.loc, new Vector2f());
659
660 float distPerp = Math.abs(Vector2f.dot(curr.normal, diff));
661 float distAlong = Math.abs(Vector2f.dot(curr.dir, diff));
662
663 distPerp -= radius;
664 distAlong -= radius;
665
666 float minDistAlong = Math.max(curr.lengthToNext, curr.lengthToPrev);
667 float fadeDistAlong = 500f + minDistAlong;
668 if (distPerp < curr.width / 2f &&
669 distAlong < fadeDistAlong) {
670 if (distAlong < minDistAlong) {
671 curr.fader.forceOut();
672 curr.bMult = 0f;
673 } else {
674 curr.bMult = Math.min(curr.bMult,
675 (distAlong - minDistAlong) / (fadeDistAlong - minDistAlong));
676 }
677 }
678 } else if (obj instanceof CampaignTerrainAPI) {
679 CampaignTerrainAPI terrain = (CampaignTerrainAPI) obj;
680 SlipstreamTerrainPlugin2 otherPlugin = (SlipstreamTerrainPlugin2) terrain.getPlugin();
681 if (otherPlugin == plugin) continue;
682
683 for (SlipstreamSegment other : otherPlugin.getSegmentsNear(curr.loc, curr.width / 2f)) {
684 //if (other.fader.getBrightness() == 0 || other.bMult <= 0) continue;
685 if (other.bMult <= 0) continue;
686
687 float dist = Misc.getDistance(curr.loc, other.loc);
688 float minDist = curr.width / 2f + other.width / 2f;
689 float fadeDist = minDist + 500f;
690 if (dist < fadeDist) {
691 if (dist < minDist) {
692 curr.fader.forceOut();
693 curr.bMult = 0f;
694 otherStreamCuts.add(curr);
695 } else {
696 curr.bMult = Math.min(curr.bMult,
697 (dist - minDist) / (fadeDist - minDist));
698 }
699 }
700 }
701 } else if (obj instanceof CustomStreamBlocker) {
702 CustomStreamBlocker blocker = (CustomStreamBlocker) obj;
703 Vector2f loc = blocker.loc;
704 float radius = blocker.radius;
705
706 Vector2f diff = Vector2f.sub(loc, curr.loc, new Vector2f());
707 float distPerp = Math.abs(Vector2f.dot(curr.normal, diff));
708 float distAlong = Math.abs(Vector2f.dot(curr.dir, diff));
709
710 distPerp -= radius;
711 distAlong -= radius;
712
713 float minDistAlong = Math.max(curr.lengthToNext, curr.lengthToPrev);
714 float fadeDistAlong = 500f + minDistAlong;
715 if (distPerp < curr.width / 2f &&
716 distAlong < fadeDistAlong) {
717 if (distAlong < minDistAlong) {
718 curr.fader.forceOut();
719 curr.bMult = 0f;
720 } else {
721 curr.bMult = Math.min(curr.bMult,
722 (distAlong - minDistAlong) / (fadeDistAlong - minDistAlong));
723 }
724 }
725 } else if (obj instanceof AbyssStreamBlocker) {
726 AbyssStreamBlocker abyss = (AbyssStreamBlocker) obj;
727 if (abyss.containsPoint(curr.loc)) {
728 curr.fader.forceOut();
729 curr.bMult = 0f;
730 }
731 }
732 }
733 }
734
735 fadeOutSectionsShorterThan(segments, 5000f);
736
737 // unrelated to the above - for proximity-to-something fades that
738 // were unnecessary because there wasn't an actual intersection with that something
740
741
742
743 if (onlyKeepLongestBetweenStreams) {
744 List<SlipstreamSegment> longest = new ArrayList<SlipstreamTerrainPlugin2.SlipstreamSegment>();
745
746 List<SlipstreamSegment> currList = new ArrayList<SlipstreamTerrainPlugin2.SlipstreamSegment>();
747
748 for (SlipstreamSegment curr : segments) {
749 if (otherStreamCuts.contains(curr)) {
750 if (currList.size() > longest.size()) {
751 longest = currList;
752 }
753 currList = new ArrayList<SlipstreamSegment>();
754 }
755 if (curr.bMult > 0f) {
756 currList.add(curr);
757 }
758 }
759 if (currList.size() > longest.size()) {
760 longest = currList;
761 }
762 for (SlipstreamSegment curr : segments) {
763 if (!longest.contains(curr)) {
764 curr.bMult = 0f;
765 curr.fader.forceOut();
766 }
767 }
768
769 }
770 }
771
772
773 public static void fadeOutSectionsShorterThan(List<SlipstreamSegment> segments, float minLength) {
774 float minRunLength = minLength;
775 List<SlipstreamSegment> currRun = new ArrayList<SlipstreamSegment>();
776 for (SlipstreamSegment curr : segments) {
777 if (curr.bMult <= 0f) {
778 float runLength = 0f;
779 for (SlipstreamSegment inRun : currRun) {
780 runLength += inRun.lengthToNext; // counts one more than it should; meh
781 }
782 if (runLength < minRunLength) {
783 for (SlipstreamSegment inRun : currRun) {
784 inRun.fader.forceOut();
785 inRun.bMult = 0f;
786 }
787 }
788 currRun.clear();
789 } else {
790 currRun.add(curr);
791 }
792 }
793 }
794
795 public static void removedFadesThatDoNotReachZero(List<SlipstreamSegment> segments) {
796 List<SlipstreamSegment> currRun = new ArrayList<SlipstreamSegment>();
797 boolean currRunReachedZero = false;
798 for (SlipstreamSegment curr : segments) {
799 if (curr.bMult < 1f) {
800 currRun.add(curr);
801 if (curr.bMult <= 0f || (curr.fader.getBrightness() == 0 && !curr.fader.isFadingIn())) {
802 currRunReachedZero = true;
803 }
804 } else {
805 if (!currRunReachedZero) {
806 for (SlipstreamSegment inRun : currRun) {
807 inRun.fader.fadeIn();
808 inRun.bMult = 1f;
809 }
810 }
811 currRun.clear();
812 currRunReachedZero = false;
813 }
814 }
815 }
816
817
818
819 public static class CustomStreamRevealer extends CustomStreamBlocker {
820 public CustomStreamRevealer(Vector2f loc, float radius) {
821 super(loc, radius);
822 }
823 }
824
825 public static class CustomStreamBlocker {
826 public Vector2f loc;
827 public float radius;
828 public CustomStreamBlocker(Vector2f loc, float radius) {
829 this.loc = new Vector2f(loc);
830 this.radius = radius;
831 }
832 }
833 public static class AbyssStreamBlocker {
834 public HyperspaceAbyssPlugin plugin;
835 public AbyssStreamBlocker() {
836 CampaignTerrainAPI terrain = Misc.getHyperspaceTerrain();
837 if (terrain != null) {
838 this.plugin = ((HyperspaceTerrainPlugin) terrain.getPlugin()).getAbyssPlugin();
839 }
840 }
841 public boolean containsPoint(Vector2f loc) {
842 if (plugin == null) return false;
843 return plugin.getAbyssalDepth(loc) > 0;
844 }
845 }
846
847 public CollisionGridUtil getGrid() {
848 return grid;
849 }
850
851 public void updateGrid() {
852 if (grid != null) return;
853
854 float sw = Global.getSettings().getFloat("sectorWidth");
855 float sh = Global.getSettings().getFloat("sectorHeight");
856 float minCellSize = 12000f;
857 float cellSize = Math.max(minCellSize, sw * 0.05f);
858
859 grid = new CollisionGridUtil(-sw/2f, sw/2f, -sh/2f, sh/2f, cellSize);
860
861 LocationAPI hyperspace = Global.getSector().getHyperspace();
862 for (SectorEntityToken jp : hyperspace.getJumpPoints()) {
863 float size = jp.getRadius() * 2f + 100f;
864 grid.addObject(jp, jp.getLocation(), size * 2f, size * 2f);
865 }
866
867// for (NascentGravityWellAPI well : hyperspace.getGravityWells()) {
868// float size = 1000f + well.getRadius();
869// CustomStreamBlocker blocker = new CustomStreamBlocker(well.getLocation(), size);
870// grid.addObject(blocker, well.getLocation(), size * 2f, size * 2f);
871// }
872 Object alphaSiteWell = Global.getSector().getMemoryWithoutUpdate().get(TTBlackSite.NASCENT_WELL_KEY);
873 if (alphaSiteWell instanceof NascentGravityWellAPI) {
874 NascentGravityWellAPI well = (NascentGravityWellAPI) alphaSiteWell;
875 float size = 1000f + well.getRadius();
876 CustomStreamBlocker blocker = new CustomStreamBlocker(well.getLocation(), size);
877 grid.addObject(blocker, well.getLocation(), size * 2f, size * 2f);
878 }
879
880 for (StarSystemAPI system : Global.getSector().getStarSystems()) {
881 if (system.hasTag(Tags.THEME_CORE)) {
882 Vector2f loc = system.getLocation();
883 float size = 4000f;
884 CustomStreamBlocker blocker = new CustomStreamBlocker(loc, size);
885 grid.addObject(blocker, loc, size * 2f, size * 2f);
886 }
887 }
888
889 {
890 float w = Global.getSettings().getFloat("sectorWidth");
891 float h = Global.getSettings().getFloat("sectorHeight");
892// Vector2f loc = new Vector2f(-w/2f, -h/2f);
893// float size = 26000;
894// CustomStreamBlocker orionPersusAbyssBlocker = new CustomStreamBlocker(loc, size);
895// grid.addObject(orionPersusAbyssBlocker, loc, size * 2f, size * 2f);
896 AbyssStreamBlocker orionPersusAbyssBlocker = new AbyssStreamBlocker();
897 grid.addObject(orionPersusAbyssBlocker, new Vector2f(), w, h);
898 }
899
900// for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
901// if (market.isHidden()) continue;
902// //if (market.hasIndustry(Industries.SPACEPORT)) continue;
903// Industry spaceport = market.getIndustry(Industries.SPACEPORT);
904// if (spaceport == null || !spaceport.isFunctional()) continue;
905//
906// Vector2f loc = market.getLocationInHyperspace();
907// float size = 5000f;
908// CustomStreamRevealer revealer = new CustomStreamRevealer(loc, size);
909// grid.addObject(revealer, loc, size * 2f, size * 2f);
910// }
911
912
913 int segmentsToSkip = (int) ((cellSize - 2000) / 400f);
914 float checkSize = minCellSize - 2000f;
915
916 for (CampaignTerrainAPI curr : hyperspace.getTerrainCopy()) {
917 if (curr.getPlugin() instanceof SlipstreamTerrainPlugin2) {
918 SlipstreamTerrainPlugin2 plugin = (SlipstreamTerrainPlugin2) curr.getPlugin();
919 List<SlipstreamSegment> segments = plugin.getSegments();
920 List<SlipstreamSegment> check = new ArrayList<SlipstreamTerrainPlugin2.SlipstreamSegment>();
921 for (int i = 0; i < segments.size(); i += segmentsToSkip) {
922 check.add(segments.get(i));
923 }
924 if (!check.contains(segments.get(segments.size() - 1))) {
925 check.add(segments.get(segments.size() - 1));
926 }
927
928 for (SlipstreamSegment seg : check) {
929 grid.addObject(curr, seg.loc, checkSize, checkSize);
930 }
931 }
932 }
933
934 ListenerUtil.updateSlipstreamBlockers(grid, this);
935 }
936
937
938 public boolean isDone() {
939 return false;
940 }
941
942 public boolean runWhilePaused() {
943 return false;
944 }
945
946
947
948}
static SettingsAPI getSettings()
Definition Global.java:51
static SectorAPI getSector()
Definition Global.java:59
void buildToDestination(Vector2f control, Vector2f control2, Vector2f to)
static void fadeOutSectionsShorterThan(List< SlipstreamSegment > segments, float minLength)
void checkIntersectionsAndFadeSections(SlipstreamTerrainPlugin2 plugin, boolean onlyKeepLongestBetweenStreams)
static void removedFadesThatDoNotReachZero(List< SlipstreamSegment > segments)
List< SlipstreamSegment > getSegmentsNear(Vector2f loc, float range)