Starsector API
Loading...
Searching...
No Matches
SlipstreamTerrainPlugin2.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.velfield;
2
3import java.util.ArrayList;
4import java.util.EnumSet;
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 java.awt.Color;
14
15import org.lwjgl.input.Mouse;
16import org.lwjgl.opengl.GL11;
17import org.lwjgl.opengl.GL14;
18import org.lwjgl.util.vector.Vector2f;
19
20import com.fs.starfarer.api.Global;
21import com.fs.starfarer.api.campaign.CampaignEngineLayers;
22import com.fs.starfarer.api.campaign.CampaignFleetAPI;
23import com.fs.starfarer.api.campaign.SectorEntityToken;
24import com.fs.starfarer.api.campaign.TerrainAIFlags;
25import com.fs.starfarer.api.combat.ViewportAPI;
26import com.fs.starfarer.api.fleet.FleetMemberViewAPI;
27import com.fs.starfarer.api.graphics.SpriteAPI;
28import com.fs.starfarer.api.impl.campaign.DebugFlags;
29import com.fs.starfarer.api.impl.campaign.abilities.ReversePolarityToggle;
30import com.fs.starfarer.api.impl.campaign.abilities.SustainedBurnAbility;
31import com.fs.starfarer.api.impl.campaign.ghosts.SensorGhost;
32import com.fs.starfarer.api.impl.campaign.ghosts.SensorGhostManager;
33import com.fs.starfarer.api.impl.campaign.ids.Entities;
34import com.fs.starfarer.api.impl.campaign.ids.Stats;
35import com.fs.starfarer.api.impl.campaign.ids.Tags;
36import com.fs.starfarer.api.impl.campaign.terrain.BaseTerrain;
37import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin;
38import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin.CellState;
39import com.fs.starfarer.api.loading.Description.Type;
40import com.fs.starfarer.api.ui.TooltipMakerAPI;
41import com.fs.starfarer.api.util.FaderUtil;
42import com.fs.starfarer.api.util.FaderUtil.State;
43import com.fs.starfarer.api.util.Misc;
44import com.fs.starfarer.api.util.MutatingVertexUtil;
45import com.fs.starfarer.api.util.WeightedRandomPicker;
46
48
49 public static float FUEL_USE_MULT = 0.5f;
50 public static String FUEL_USE_MODIFIER_DESC = "Inside slipstream";
51
52 public static class SlipstreamParams2 {
53 public String enteringSlipstreamTextOverride = null;
54 public Float enteringSlipstreamTextDurationOverride = null;
55 public boolean forceNoWindVisualEffectOnFleets = false;
56 public String spriteKey1 = "slipstream0";
57 public String spriteKey2 = "slipstream1";
58 public String spriteKey3 = "slipstream2";
59 public String edgeKey = "slipstream_edge";
60 public Color spriteColor = Color.white;
61 public Color windGlowColor = new Color(0.65f, 0.5f, 1f, 0.75f);
62 public Color edgeColor = Color.white;
63 public float baseWidth = 768f;
64 public float widthForMaxSpeed = 768f;
65 public float edgeWidth = 256f;
66 public float areaPerParticle = 10000;
67 public int maxParticles = 2000;
68 public float minSpeed;
69 public float maxSpeed;
70 public Color minColor = new Color(0.5f, 0.3f, 0.75f, 0.1f);
71 public Color maxColor = new Color(0.5f, 0.6f, 1f, 0.3f);
72 public Color mapColor = new Color(0.5f, 0.6f, 1f, 1f);
73 //public Color maxColor = new Color(0.5f, 0.6f, 1f, 0.5f);
74 public float minDur = 2f;
75 public float maxDur = 6f;
76 public float particleFadeInTime = 1f;
77 public float lineLengthFractionOfSpeed = 0.25f;
78
79 public int burnLevel = 30;
80 public int maxBurnLevelForTextureScroll = 30;
81 public boolean slowDownInWiderSections = true;
82 public float widthForMaxSpeedMinMult = 0.67f;
83 public float widthForMaxSpeedMaxMult = 1.5f;
84 public float accelerationMult = 1f;
85 public String name = null;
86
87 public float texScrollMult0 = 0f;
88 public float texScrollMult1 = -1.13f;
89 public float texScrollMult2 = -0.28f;
90
91 Object readResolve() {
92 if (accelerationMult <= 0f) {
93 accelerationMult = 1f;
94 }
95 return this;
96 }
97 }
98
99 public static class SlipstreamSegment {
100 public Vector2f loc = new Vector2f();
101 public float width;
102 public float bMult = 1f;
103
104 transient public Vector2f locB = new Vector2f();
105 transient public Vector2f dir = new Vector2f();
106 transient public float wobbledWidth;
107 transient public int index = 0;
108 transient public Vector2f normal = new Vector2f();
109 transient public float tx = 0f;
110 transient public float txe1 = 0f;
111 transient public float txe2 = 0f;
112 transient public float totalLength;
113 transient public float lengthToPrev;
114 transient public float lengthToNext;
115
116 transient public MutatingVertexUtil wobble1;
117 transient public MutatingVertexUtil wobble2;
118 public FaderUtil fader = new FaderUtil(0f, 1f, 1f);
119
120 public boolean discovered = false;
121
122 public Object readResolve() {
123 float minRadius = 0f;
124 float maxRadius = width * 0.05f;
125 float rate = maxRadius * 0.5f;
126 float angleRate = 50f;
127 wobble1 = new MutatingVertexUtil(minRadius, maxRadius, rate, angleRate);
128 wobble2 = new MutatingVertexUtil(minRadius, maxRadius, rate, angleRate);
129 locB = new Vector2f();
130 return this;
131 }
132 }
133
134 public static class SlipstreamParticle {
135 float speed;
136 float dist;
137 float yPos;
138 Color color;
139 float remaining;
140 float elapsed;
141 }
142
143 public static int MAX_PARTICLES_ADD_PER_FRAME = 250;
144
145 public static float RAD_PER_DEG = 0.01745329251f;
146 public static Vector2f rotateAroundOrigin(Vector2f v, float cos, float sin) {
147 Vector2f r = new Vector2f();
148 r.x = v.x * cos - v.y * sin;
149 r.y = v.x * sin + v.y * cos;
150 return r;
151 }
152
153
154
155 protected SlipstreamParams2 params = new SlipstreamParams2();
156
157 protected List<SlipstreamSegment> segments = new ArrayList<SlipstreamTerrainPlugin2.SlipstreamSegment>();
158 protected float totalLength = 0f;
159
160 protected transient List<Vector2f> encounterPoints = new ArrayList<Vector2f>();
161
162 protected transient List<SlipstreamParticle> particles = new ArrayList<SlipstreamParticle>();
163 protected transient int [] lengthToIndexMap;
164 protected transient int lengthDivisor;
165
166 protected boolean needsRecompute = true;
167 transient protected List<BoundingBox> bounds = new ArrayList<BoundingBox>();
168 protected int segmentsPerBox;
169
170 protected float texProgress0 = 0f;
171 protected float texProgress1 = 0f;
172 protected float texProgress2 = 0f;
173 //protected transient float mapArrowProgress = 0f;
174
175 protected float [] despawnNoise = null;
176 protected float despawnDelay = 0f;
177 protected float despawnDays = 0f;
178 protected float despawnElapsed = 0f;
179
180 protected float [] spawnNoise = null;
181 protected float spawnDays = 0f;
182 protected float spawnElapsed = 0f;
183 protected boolean dynamic = false;
184
186 }
187
188 public boolean isDespawning() {
190 }
191
192 public void spawn(float spawnDays, Random random) {
193 //if (true) return;
194 this.spawnDays = spawnDays;
195 spawnElapsed = 0f;
196
197 int numNoisePoints = 32;
198 while (numNoisePoints < segments.size()) {
199 numNoisePoints *= 2f;
200 }
201 if (numNoisePoints > 512) numNoisePoints = 512;
202
203 float spikes = 0.67f;
204 spawnNoise = SlipstreamBuilder.initNoise1D(random, numNoisePoints, spikes);
205 spawnNoise[0] = 0.5f;
206 spawnNoise[spawnNoise.length - 1] = 0.5f;
207 SlipstreamBuilder.genNoise1D(random, spawnNoise, numNoisePoints, spikes);
209 }
210
211 protected void advanceSpawn(float amount) {
212 if (spawnNoise == null) return;
213 if (despawnElapsed > 0 || despawnDays > 0) return;
214
215 float days = Global.getSector().getClock().convertToDays(amount);
216
217 spawnElapsed += days;
218 float f = spawnElapsed / Math.max(0.1f, spawnDays);
219
220 float size = segments.size();
221 boolean allFadedIn = true;
222 for (SlipstreamSegment seg : segments) {
223 allFadedIn &= seg.fader.isFadedIn();
224
225 float t = (seg.index + 1) / size;
227 if (noise <= f || f >= 1f) {
228 float dur = Math.max(1f, Global.getSector().getClock().convertToSeconds((spawnDays - spawnElapsed) / 2f));
229 seg.fader.setDurationIn(dur);
230 seg.fader.fadeIn();
231 } else {
232 seg.fader.fadeOut();
233 }
234 }
235 if (allFadedIn) {
236 spawnNoise = null;
237 spawnElapsed = 0;
238 spawnDays = 0;
239 }
240 }
241
242 public void despawn(float despawnDelay, float despawnDays, Random random) {
243 this.despawnDays = despawnDays;
244 this.despawnDelay = despawnDelay;
245 despawnElapsed = 0f;
246
247 int numNoisePoints = 32;
248 while (numNoisePoints < segments.size()) {
249 numNoisePoints *= 2f;
250 }
251 if (numNoisePoints > 512) numNoisePoints = 512;
252
253 float spikes = 0.67f;
254 despawnNoise = SlipstreamBuilder.initNoise1D(random, numNoisePoints, spikes);
255 despawnNoise[0] = 0.5f;
256 despawnNoise[despawnNoise.length - 1] = 0.5f;
257 SlipstreamBuilder.genNoise1D(random, despawnNoise, numNoisePoints, spikes);
259 }
260
261 protected void advanceDespawn(float amount) {
262// if (isDespawning()) {
263// System.out.println("3f23f23f32");
264// }
265 if (despawnNoise == null) return;
267
268 float days = Global.getSector().getClock().convertToDays(amount);
269 despawnDelay -= days;
270 if (despawnDelay > 0) return;
271
272 despawnElapsed += days;
273 float f = despawnElapsed / Math.max(0.1f, despawnDays);
274
275 float size = segments.size();
276 boolean allFaded = true;
277 for (SlipstreamSegment seg : segments) {
278 allFaded &= seg.fader.isFadedOut();
279
280 float t = (seg.index + 1) / size;
282 if (noise <= f || f >= 1f) {
283 float dur = Math.max(1f, Global.getSector().getClock().convertToSeconds((despawnDays - despawnElapsed) / 2f));
284 seg.fader.setDurationOut(dur);
285 seg.fader.fadeOut();
286 }
287 }
288 if (allFaded) {
290 despawnNoise = null;
291 }
292 }
293
294 public void setNeedsRecompute() {
295 this.needsRecompute = true;
296 }
297
299 float minSegmentLength = Float.MAX_VALUE;
300 for (SlipstreamSegment curr : segments) {
301 if (curr.lengthToNext > 0 && minSegmentLength > curr.lengthToNext) {
302 minSegmentLength = curr.lengthToNext;
303 }
304 }
305 if (minSegmentLength < 50f) minSegmentLength = 50f;
306
307 lengthDivisor = (int) (minSegmentLength - 1f);
308 int numIndices = (int) (totalLength / lengthDivisor);
309 lengthToIndexMap = new int [numIndices];
310
311 int lengthSoFar = 0;
312 for (int i = 0; i < segments.size(); i++) {
313 SlipstreamSegment curr = segments.get(i);
314 while (lengthSoFar < curr.totalLength + curr.lengthToNext) {
315 int lengthIndex = lengthSoFar / lengthDivisor;
316 if (lengthIndex < lengthToIndexMap.length) {
317 lengthToIndexMap[lengthIndex] = i;
318 }
319 lengthSoFar += lengthDivisor;
320 }
321 }
322 }
323
324 public SlipstreamSegment getSegmentForDist(float distAlongStream) {
325 if (lengthToIndexMap == null) return null;
326 int mapIndex = (int) (distAlongStream / lengthDivisor);
327 if (mapIndex < 0 || mapIndex >= lengthToIndexMap.length) return null;
328 //System.out.println("Index: " + mapIndex + ", dist: " + distAlongStream);
329 int segIndex = lengthToIndexMap[mapIndex];
330 SlipstreamSegment segment = segments.get(segIndex);
331 while (distAlongStream < segment.totalLength) {
332 segIndex--;
333 if (segIndex < 0) return null;
334 segment = segments.get(segIndex);
335 }
336 while (distAlongStream > segment.totalLength + segment.lengthToNext) {
337 segIndex++;
338 if (segIndex >= segments.size()) return null;
339 segment = segments.get(segIndex);
340 }
341 return segment;
342 }
343
344 public void addSegment(Vector2f loc, float width) {
345 SlipstreamSegment s = new SlipstreamSegment();
346 s.loc.set(loc);
347 s.width = width;
348 s.wobbledWidth = width - params.edgeWidth * 2f * 0.25f;
349
350 float minRadius = 0f;
351 float maxRadius = s.width * 0.05f;
352 float rate = maxRadius * 0.5f;
353 float angleRate = 50f;
354 s.wobble1 = new MutatingVertexUtil(minRadius, maxRadius, rate, angleRate);
355 s.wobble2 = new MutatingVertexUtil(minRadius, maxRadius, rate, angleRate);
356
357 s.fader.fadeIn();
358
359 segments.add(s);
361 }
362
363 public void init(String terrainId, SectorEntityToken entity, Object pluginParams) {
364 super.init(terrainId, entity, pluginParams);
365 this.params = (SlipstreamParams2) pluginParams;
366 readResolve();
367 }
368
369 public float getRenderRange() {
370 return totalLength * 0.6f + 1000f;
371 //return totalLength + 1000f;
372 }
373
374 Object readResolve() {
375 particles = new ArrayList<SlipstreamParticle>();
376 bounds = new ArrayList<BoundingBox>();
377
378 needsRecompute = true;
379 layers = EnumSet.of(CampaignEngineLayers.TERRAIN_SLIPSTREAM);
380 return this;
381 }
382
383 public void advance(float amount) {
384 super.advance(amount);
385 if (amount <= 0) {
386 return; // happens during game load
387 }
389 applyEffectToEntities(amount);
390 doSoundPlayback(amount);
391 }
392
393// for (SlipstreamSegment seg : getSegments()) {
394// seg.fader.fadeOut();
395// seg.fader.fadeIn();
396// }
397// float countWithLowBMult = 0f;
398// for (SlipstreamSegment seg : getSegments()) {
399// if (seg.bMult < 1f) {
400// countWithLowBMult++;
401// }
402// }
403// System.out.println("WITH LOW bMult from STP2: " + countWithLowBMult);
404
405
407 advanceNearbySegments(amount);
408
409 addParticles();
410 advanceParticles(amount);
411
412 advanceSpawn(amount);
413 advanceDespawn(amount);
414
416 float texSpeed = Misc.getSpeedForBurnLevel(Math.min(params.burnLevel * 0.5f,
417 params.maxBurnLevelForTextureScroll));
418
419 SpriteAPI sprite = Global.getSettings().getSprite("misc", params.spriteKey1);
420
421 float texelsPerPixel = 1f;
422 if (segments.size() > 1) {
423 texelsPerPixel = (segments.get(1).tx * sprite.getWidth()) / Math.max(1f, segments.get(1).lengthToPrev);
424 }
425
426 float unitsPerOneTexIter = sprite.getWidth();
427 float texUnitsPerSecondForSpeed = texSpeed / unitsPerOneTexIter * texelsPerPixel;
428 texProgress0 -= texUnitsPerSecondForSpeed * amount * params.texScrollMult0;
429 texProgress1 += texUnitsPerSecondForSpeed * amount * params.texScrollMult1;
430 texProgress2 += texUnitsPerSecondForSpeed * amount * params.texScrollMult2;
431 if (texProgress0 > 100000) texProgress0 -= 100000f;
432 if (texProgress1 > 100000) texProgress1 -= 100000f;
433 if (texProgress2 > 100000) texProgress2 -= 100000f;
434 }
435 }
436
437 public boolean isDynamic() {
438 return dynamic;
439 }
440
441 public void setDynamic(boolean dynamic) {
442 this.dynamic = dynamic;
443 }
444
445 public void recomputeIfNeeded() {
446 if (!needsRecompute) return;
447 recompute();
448 }
449
450 public void recompute() {
451 needsRecompute = false;
452
453 // compute average location, set segment indices
454 Vector2f avgLoc = new Vector2f();
455 for (int i = 0; i < segments.size(); i++) {
456 SlipstreamSegment curr = segments.get(i);
457 curr.index = i;
458 Vector2f.add(avgLoc, curr.loc, avgLoc);
459 }
460
461 if (segments.size() > 0) {
462 avgLoc.scale(1f / segments.size());
463 entity.setLocation(avgLoc.x, avgLoc.y);
464 }
465
466
467 SpriteAPI sprite = Global.getSettings().getSprite("misc", params.spriteKey1);
468 SpriteAPI edge = Global.getSettings().getSprite("misc", params.edgeKey);
469
470 // compute texture coordinates etc
471 float tx = 0f;
472 float txe1 = 0f;
473 float txe2 = 0f;
474 float totalLength = 0f;
475 for (int i = 0; i < segments.size(); i++) {
476 SlipstreamSegment prev = null;
477 if (i > 0) prev = segments.get(i - 1);
478 SlipstreamSegment curr = segments.get(i);
479 SlipstreamSegment next = null;
480 SlipstreamSegment next2 = null;
481 SlipstreamSegment next3 = null;
482 if (i < segments.size() - 1) {
483 next = segments.get(i + 1);
484 }
485 if (i < segments.size() - 2) {
486 next2 = segments.get(i + 2);
487 }
488 if (i < segments.size() - 3) {
489 next3 = segments.get(i + 3);
490 }
491
492 if (curr.dir == null) curr.dir = new Vector2f();
493 if (curr.normal == null) curr.normal = new Vector2f();
494
495 if (next == null) {
496 if (prev != null) {
497 curr.dir.set(prev.dir);
498 }
499 } else {
500 Vector2f dir = Vector2f.sub(next.loc, curr.loc, new Vector2f());
501 dir = Misc.normalise(dir);
502 curr.dir = dir;
503 }
504
505 Vector2f dir = curr.dir;
506 if (prev == null || next == null) {
507 curr.normal.set(-dir.y, dir.x);
508 } else {
509 Vector2f avg = Vector2f.add(prev.dir, curr.dir, new Vector2f());
510 avg.scale(0.5f);
511 curr.normal.set(-avg.y, avg.x);
512 }
513// Vector2f normal = new Vector2f(-dir.y, dir.x);
514// curr.normal.set(normal);
515
516 float length = 0f;
517 float texLength = 0f;
518 float e1TexLength = 0f;
519 float e2TexLength = 0f;
520 if (prev != null) {
521 Vector2f dir2 = Vector2f.sub(curr.loc, prev.loc, new Vector2f());
522 length = dir2.length();
523 texLength = length / sprite.getWidth();
524 if (!dynamic) {
525 texLength = Math.min(texLength, sprite.getHeight() / curr.width);
526 }
527
528 Vector2f edgeCurr = new Vector2f(curr.loc);
529 edgeCurr.x += curr.normal.x * curr.width * 0.5f;
530 edgeCurr.y += curr.normal.y * curr.width * 0.5f;
531
532 Vector2f edgePrev = new Vector2f(prev.loc);
533 edgePrev.x += prev.normal.x * prev.width * 0.5f;
534 edgePrev.y += prev.normal.y * prev.width * 0.5f;
535
536 float length2 = Vector2f.sub(edgeCurr, edgePrev, new Vector2f()).length();
537 e1TexLength = length2 / edge.getWidth() * edge.getHeight() / params.edgeWidth;
538
539
540 edgeCurr = new Vector2f(curr.loc);
541 edgeCurr.x -= curr.normal.x * curr.width * 0.5f;
542 edgeCurr.y -= curr.normal.y * curr.width * 0.5f;
543
544 edgePrev = new Vector2f(prev.loc);
545 edgePrev.x -= prev.normal.x * prev.width * 0.5f;
546 edgePrev.y -= prev.normal.y * prev.width * 0.5f;
547
548 length2 = Vector2f.sub(edgeCurr, edgePrev, new Vector2f()).length();
549 e2TexLength = length2 / edge.getWidth() * edge.getHeight() / params.edgeWidth;
550 }
551
552 tx += texLength;
553 txe1 += e1TexLength;
554 txe2 += e2TexLength;
555 curr.tx = tx;
556 curr.txe1 = txe1;
557 curr.txe2 = txe2;
558 curr.lengthToPrev = length;
559
560 totalLength += length;
561 curr.totalLength = totalLength;
562 //curr.lengthToNext = Misc.getDistance(curr.loc, next.loc);
563 if (prev != null) {
564 prev.lengthToNext = length;
565 }
566
567 if (next != null && next2 != null && next3 != null) {
568 Vector2f p0 = curr.loc;
569 Vector2f p1 = next.loc;
570 Vector2f p2 = next2.loc;
571 Vector2f p3 = next3.loc;
572
573 float p1ToP2 = Misc.getAngleInDegrees(p1, p2);
574 float p2ToP3 = Misc.getAngleInDegrees(p2, p3);
575 float diff = Misc.getAngleDiff(p1ToP2, p2ToP3);
576 float adjustment = Math.min(diff, Math.max(diff * 0.25f, diff - 10f));
577 adjustment = diff * 0.5f;
578 //adjustment = diff * 0.25f;
579 float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * adjustment * 1f + 180f;
580 //angle = Misc.getAngleInDegrees(p3, p2);
581 float dist = Misc.getDistance(p2, p1);
582 Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle);
583 p1Adjusted.scale(dist);
584 Vector2f.add(p1Adjusted, p2, p1Adjusted);
585 next.locB = p1Adjusted;
586 } else if (next != null) {
587 next.locB = next.loc;
588 }
589 if (prev == null) {
590 curr.locB = new Vector2f(curr.loc);
591 }
592 }
593 this.totalLength = totalLength;
594
597 }
598
599 protected void updateBoundingBoxes() {
600 segmentsPerBox = (int) Math.sqrt(segments.size()) + 1;
601 if (segmentsPerBox < 20) segmentsPerBox = 20;
602
603 bounds.clear();
604 for (int i = 0; i < segments.size(); i+= segmentsPerBox) {
605 List<SlipstreamSegment> section = new ArrayList<SlipstreamSegment>();
606 for (int j = i; j < i + segmentsPerBox && j < segments.size(); j++) {
607 section.add(segments.get(j));
608 }
609 if (i + segmentsPerBox < segments.size()) {
610 section.add(segments.get(i + segmentsPerBox));
611 }
612 BoundingBox box = BoundingBox.create(section);
613 bounds.add(box);
614 }
615 }
616
617 protected void advanceNearbySegments(float amount) {
618// if (isDespawning()) {
619// System.out.println("3f23f23f32");
620// }
621
623 if (pf == null || !entity.isInCurrentLocation()) {
624 if (spawnNoise != null || despawnNoise != null) {
625 for (int i = 0; i < segments.size(); i++) {
626 SlipstreamSegment curr = segments.get(i);
627 curr.fader.advance(amount);
628 }
629 }
630 return;
631 }
632
633// if (segments.size() > 0) {
634// segments.get(0).fader.forceOut();
635// segments.get(segments.size() - 1).fader.fadeOut();
636// }
637
639 float viewRadius = new Vector2f(viewport.getVisibleWidth() * 0.5f, viewport.getVisibleHeight() * 0.5f).length();
640 viewRadius = Math.max(6000f, viewRadius);
641 viewRadius += 1000f;
642 List<SlipstreamSegment> near = getSegmentsNear(viewport.getCenter(), viewRadius);
643
644 // advance faders for all segments, not just nearby, since it's not just aesthetic
645 for (int i = 0; i < segments.size(); i++) {
646// if (i == 6) {
647// System.out.println("wefwefwef");
648// }
649 SlipstreamSegment curr = segments.get(i);
650 curr.fader.advance(amount);
651 }
652
654
655// float [] c = getLengthAndWidthFractionWithinStream(pf.getLocation());
656// if (c != null) {
657// if (getSegmentForDist(c[0]) != null) {
658// System.out.println("efwefwefew");
659// for (int i = 0; i < segments.size() && i < 20; i++) {
660// System.out.println("bMult: " + segments.get(i).bMult);
661// }
662// }
663// }
664
665 // advance wobble, compute wobbledWidth
666 for (int i = 0; i < near.size(); i++) {
667 SlipstreamSegment curr = near.get(i);
668
669 if (entity.isInHyperspace() && !curr.fader.isFadedOut() &&
670 curr.fader.getBrightness() * curr.bMult > 0.05f && curr.bMult > 0f) {
671 plugin.setTileState(
672 curr.loc, curr.width * 0.5f + params.edgeWidth + 100f,
673 CellState.OFF,
674 1f - curr.fader.getBrightness(), -1f);
675 //plugin.turnOffStorms(curr.loc, curr.width * 0.5f + params.edgeWidth + 200f);
676 }
677
678 //curr.fader.advance(amount);
679
680 float r1 = 0.5f + (float) Math.random() * 1f;
681 float r2 = 0.5f + (float) Math.random() * 1f;
682 curr.wobble1.advance(amount * r1);
683 curr.wobble2.advance(amount * r2);
684// curr.wobble1.vector.set(0, 0);
685// curr.wobble2.vector.set(0, 0);
686
687 Vector2f p1 = new Vector2f(curr.loc);
688 Vector2f p2 = new Vector2f(curr.loc);
689 p1.x += curr.normal.x * curr.width * 0.5f;
690 p1.y += curr.normal.y * curr.width * 0.5f;
691 p2.x -= curr.normal.x * curr.width * 0.5f;
692 p2.y -= curr.normal.y * curr.width * 0.5f;
693
694 p1.x += curr.wobble1.vector.x;
695 p1.y += curr.wobble1.vector.y;
696 p2.x += curr.wobble2.vector.x;
697 p2.y += curr.wobble2.vector.y;
698
699 //particles.clear();
700 //curr.wobbledWidth = Misc.getDistance(p1, p2);
701 float d = Misc.getDistance(p1, p2);
702 //curr.wobbledWidth = d - params.edgeWidth * 2f * 0.5f;
703 curr.wobbledWidth = d - params.edgeWidth * 2f * 0.25f;
704 if (curr.wobbledWidth < d * 0.5f) curr.wobbledWidth = d * 0.5f;
705 //curr.wobbledWidth = curr.width;
706
707 if (curr.index > 0) {
708 SlipstreamSegment prev = segments.get(curr.index - 1);
709 Vector2f prev1 = new Vector2f(prev.loc);
710 Vector2f prev2 = new Vector2f(prev.loc);
711 prev1.x += prev.normal.x * prev.width * 0.5f;
712 prev1.y += prev.normal.y * prev.width * 0.5f;
713 prev2.x -= prev.normal.x * prev.width * 0.5f;
714 prev2.y -= prev.normal.y * prev.width * 0.5f;
715
716 float wobbleMult = 0.33f;
717 wobbleMult = 0.4f;
718 float maxWobbleRadius = Math.min(prev.width, curr.width) * 0.05f;
719 float maxWobble1 = Misc.getDistance(p1, prev1) * wobbleMult;
720 float maxWobble2 = Misc.getDistance(p2, prev2) * wobbleMult;
721 maxWobble1 = Math.min(maxWobbleRadius, maxWobble1);
722 maxWobble2 = Math.min(maxWobbleRadius, maxWobble2);
723
724 if (curr.index < segments.size() - 1) {
725 SlipstreamSegment next = segments.get(curr.index + 1);
726 Vector2f next1 = new Vector2f(next.loc);
727 Vector2f next2 = new Vector2f(next.loc);
728 next1.x += next.normal.x * next.width * 0.5f;
729 next1.y += next.normal.y * next.width * 0.5f;
730 next2.x -= next.normal.x * next.width * 0.5f;
731 next2.y -= next.normal.y * next.width * 0.5f;
732 maxWobbleRadius = Math.min(next.width, curr.width) * 0.05f;
733 float maxWobble1A = Misc.getDistance(p1, next1) * wobbleMult;
734 float maxWobble2A = Misc.getDistance(p2, next2) * wobbleMult;
735 maxWobble1 = Math.min(maxWobble1, maxWobble1A);
736 maxWobble2 = Math.min(maxWobble2, maxWobble2A);
737 }
738
739 prev.wobble1.radius.setMax(maxWobble1);
740 prev.wobble2.radius.setMax(maxWobble2);
741 curr.wobble1.radius.setMax(maxWobble1);
742 curr.wobble2.radius.setMax(maxWobble2);
743 }
744 }
745 }
746
747
748
749 public void addParticles() {
750 if (Global.getSector().getPlayerFleet() == null) {
751 particles.clear();
752 return;
753 }
754
755 boolean useNewSpawnMethod = true;
756 //useNewSpawnMethod = false;
757
758 if (useNewSpawnMethod) {
759 boolean inCurrentLocation = entity.isInCurrentLocation();
760 boolean inHyperspace = entity.isInHyperspace();
761 boolean spawnForAllSegments = false;
763 Vector2f locFrom = viewport.getCenter();
764 float viewRadius = new Vector2f(viewport.getVisibleWidth() * 0.5f, viewport.getVisibleHeight() * 0.5f).length();
765 viewRadius += 2000f;
766 viewRadius = Math.max(viewRadius, 10000f);
767 if (!inCurrentLocation) {
768 if (inHyperspace) {
769 viewRadius = 5000f;
771 } else {
772 float dist = Misc.getDistanceToPlayerLY(entity);
773 spawnForAllSegments = dist < 2f;
774 }
775 }
776 Set<SlipstreamSegment> veryNearSet = new LinkedHashSet<SlipstreamTerrainPlugin2.SlipstreamSegment>();
777 if (inCurrentLocation) {
778 float veryNearRadius = new Vector2f(viewport.getVisibleWidth() * 0.5f, viewport.getVisibleHeight() * 0.5f).length();
779 viewRadius += 500f;
780 veryNearSet = new LinkedHashSet<SlipstreamTerrainPlugin2.SlipstreamSegment>(
781 getSegmentsNear(viewport.getCenter(), veryNearRadius));
782 }
783
784 // viewRadius *= 0.5f;
785 // viewRadius = 500f;
786
787 List<SlipstreamSegment> near;
788 if (spawnForAllSegments) {
789 near = new ArrayList<SlipstreamSegment>(segments);
790 } else {
791 near = getSegmentsNear(locFrom, viewRadius);
792 }
793 Set<SlipstreamSegment> nearSet = new LinkedHashSet<SlipstreamSegment>(near);
794
795 Map<SlipstreamSegment, List<SlipstreamParticle>> particleMap = new LinkedHashMap<SlipstreamTerrainPlugin2.SlipstreamSegment, List<SlipstreamParticle>>();
796 //for (SlipstreamParticle p : particles) {
797 Iterator<SlipstreamParticle> iter = particles.iterator();
798 while (iter.hasNext()) {
799 SlipstreamParticle p = iter.next();
800 SlipstreamSegment seg = getSegmentForDist(p.dist);
801 if (seg != null) {
802 if (!nearSet.contains(seg)) {
803 iter.remove();
804 continue;
805 }
806
807 List<SlipstreamParticle> list = particleMap.get(seg);
808 if (list == null) {
809 list = new ArrayList<SlipstreamTerrainPlugin2.SlipstreamParticle>();
810 particleMap.put(seg, list);
811 }
812 list.add(p);
813 }
814 }
815
816
817 float totalArea = 0f;
818 int nearParticles = 0;
820
821 // figure out how many particles to add total, and also which segments to add them
822 // to to achieve a relatively even distribution
823 for (int i = 0; i < near.size(); i++) {
824 SlipstreamSegment curr = near.get(i);
825 if (curr.lengthToNext <= 0) continue; // last segment, can't have particles in it since the stream is over
826
827 float area = curr.lengthToNext * curr.width;
828 float desiredParticles = area / params.areaPerParticle;
829 if (desiredParticles < 1) desiredParticles = 1;
830
831 float particlesInSegment = 0;
832 List<SlipstreamParticle> list = particleMap.get(curr);
833 if (list != null) {
834 particlesInSegment = list.size();
835 }
836
837 float mult = 1f;
838 // spawn more particles in visible/nearly visible areas
839 // better to have less visible particles when the player zooms out while paused
840 // than to have less visible particles when zoomed in
841 if (veryNearSet.contains(curr)) mult = 10f;
842
843 float w = desiredParticles - particlesInSegment;
844 w *= mult;
845 if (w < 5f) w = 5f;
846 segmentPicker.add(curr, w);
847 //segmentPicker.add(curr, 1f);
848
849 totalArea += area;
850 nearParticles += particlesInSegment;
851 }
852
853
854 int numParticlesBasedOnArea = (int) (totalArea / params.areaPerParticle);
855 int actualDesired = numParticlesBasedOnArea;
856 if (numParticlesBasedOnArea < 10) numParticlesBasedOnArea = 10;
857 if (numParticlesBasedOnArea > params.maxParticles) numParticlesBasedOnArea = params.maxParticles;
858 //System.out.println("Area: " + totalArea/params.numParticles);
859 //numParticlesBasedOnArea = 20000;
860
861
862 int particlesToAdd = numParticlesBasedOnArea - nearParticles;
863 if (particlesToAdd > MAX_PARTICLES_ADD_PER_FRAME) {
864 particlesToAdd = MAX_PARTICLES_ADD_PER_FRAME;
865 }
866 particlesToAdd = Math.min(particlesToAdd, params.maxParticles - particles.size());
867
868 int added = 0;
869 while (added < particlesToAdd) {
870 added++;
871 SlipstreamSegment seg = segmentPicker.pick();
872 if (seg == null) continue;
873
874 SlipstreamParticle p = new SlipstreamParticle();
875 float fLength = (float) Math.random() * 1f;
876 float fWidth = (float) Math.random() * 2f - 1f;
877
878 float speed = params.minSpeed + (params.maxSpeed - params.minSpeed) * (float) Math.random();
879 float dur = params.minDur + (params.maxDur - params.minDur) * (float) Math.random();
880
881 p.yPos = fWidth;
882 //p.dist = totalLength * fLength;
883 p.dist = seg.totalLength + seg.lengthToNext * fLength;
884 p.speed = speed;
885
886 float intensity = getIntensity(p.yPos);
887 float wMult = getWidthBasedSpeedMult(p.dist);
888 // if (wMult <= 0) {
889 // getWidthBasedSpeedMult(p.dist);
890 // }
891 float speedMult = (0.65f + 0.35f * intensity) * wMult;
892 p.speed *= speedMult;
893
894 p.remaining = dur;
895 p.color = getRandomColor();
896
897 particles.add(p);
898 }
899
900 //System.out.println("Particles: " + particles.size() + " desired based on area: " + actualDesired);
901
902 } else {
903 float totalArea = 0f;
904 for (int i = 0; i < segments.size(); i++) {
905 SlipstreamSegment curr = segments.get(i);
906 totalArea += curr.lengthToPrev * curr.width;
907 }
908
909 int numParticlesBasedOnArea = (int) (totalArea / params.areaPerParticle);
910 if (numParticlesBasedOnArea < 10) numParticlesBasedOnArea = 10;
911 if (numParticlesBasedOnArea > params.maxParticles) numParticlesBasedOnArea = params.maxParticles;
912 //System.out.println("Area: " + totalArea/params.numParticles);
913 //numParticlesBasedOnArea = 20000;
914
915
916 int added = 0;
917 //while (particles.size() < params.numParticles && added < MAX_PARTICLES_ADD_PER_FRAME) {
918 while (particles.size() < numParticlesBasedOnArea && added < MAX_PARTICLES_ADD_PER_FRAME) {
919 added++;
920
921 SlipstreamParticle p = new SlipstreamParticle();
922 float fLength = (float) Math.random() * 1f;
923 float fWidth = (float) Math.random() * 2f - 1f;
924
925 float speed = params.minSpeed + (params.maxSpeed - params.minSpeed) * (float) Math.random();
926 float dur = params.minDur + (params.maxDur - params.minDur) * (float) Math.random();
927
928 p.yPos = fWidth;
929 p.dist = totalLength * fLength;
930 p.speed = speed;
931
932 float intensity = getIntensity(p.yPos);
933 float wMult = getWidthBasedSpeedMult(p.dist);
934 // if (wMult <= 0) {
935 // getWidthBasedSpeedMult(p.dist);
936 // }
937 float speedMult = (0.65f + 0.35f * intensity) * wMult;
938 p.speed *= speedMult;
939
940 p.remaining = dur;
941 p.color = getRandomColor();
942
943 particles.add(p);
944 }
945 }
946 }
947
948 public void advanceParticles(float amount) {
949 Iterator<SlipstreamParticle> iter = particles.iterator();
950 while (iter.hasNext()) {
951 SlipstreamParticle p = iter.next();
952 p.remaining -= amount;
953 p.elapsed += amount;
954 if (p.remaining <= 0) {
955 iter.remove();
956 continue;
957 }
958
959 p.dist += p.speed * amount;
960 }
961 }
962
963 public float getWidthBasedSpeedMult(float distAlong) {
964 float mult = 1f;
965 if (params.slowDownInWiderSections) {
966 SlipstreamSegment curr = getSegmentForDist(distAlong);
967 if (curr != null) {
968 float width = curr.width;
969 if (segments.size() > curr.index + 1) {
970 SlipstreamSegment next = segments.get(curr.index + 1);
971 float f = (distAlong - curr.totalLength) / curr.lengthToNext;
972 if (f < 0) f = 0;
973 if (f > 1) f = 1;
974 width = Misc.interpolate(width, next.width, f);
975 mult = Math.min(params.widthForMaxSpeedMaxMult,
976 params.widthForMaxSpeedMinMult + (1f - params.widthForMaxSpeedMinMult) * params.widthForMaxSpeed / width);
977 }
978 }
979 }
980 return mult;
981 }
982
983 public float getWidth(float distAlong) {
984 SlipstreamSegment curr = getSegmentForDist(distAlong);
985 if (curr != null) {
986 float width = curr.width;
987 if (segments.size() > curr.index + 1) {
988 SlipstreamSegment next = segments.get(curr.index + 1);
989 float f = (distAlong - curr.totalLength) / curr.lengthToNext;
990 if (f < 0) f = 0;
991 if (f > 1) f = 1;
992 width = Misc.interpolate(width, next.width, f);
993 return width;
994 } else {
995 return curr.width;
996 }
997 }
998 return 0f;
999 }
1000 public float getWobbledWidth(float distAlong) {
1001 SlipstreamSegment curr = getSegmentForDist(distAlong);
1002 if (curr != null) {
1003 float width = curr.wobbledWidth;
1004 if (segments.size() > curr.index + 1) {
1005 SlipstreamSegment next = segments.get(curr.index + 1);
1006 float f = (distAlong - curr.totalLength) / curr.lengthToNext;
1007 if (f < 0) f = 0;
1008 if (f > 1) f = 1;
1009 width = Misc.interpolate(width, next.wobbledWidth, f);
1010 return width;
1011 } else {
1012 return curr.wobbledWidth;
1013 }
1014 }
1015 return 0f;
1016 }
1017
1018 public float getIntensity(float yOff) {
1019 yOff = Math.abs(yOff);
1020 float intensity = 1f;
1021
1022 float dropoffAt = 0.5f;
1023 dropoffAt = 0.33f;
1024 if (yOff > dropoffAt) {
1025 intensity = 1f - 1f * (yOff - dropoffAt) / (1f - dropoffAt);
1026 }
1027 return intensity;
1028 }
1029
1030 public float getFaderBrightness(float distAlong) {
1031 SlipstreamSegment curr = getSegmentForDist(distAlong);
1032 if (curr != null) {
1033 if (segments.size() > curr.index + 1) {
1034 SlipstreamSegment next = segments.get(curr.index + 1);
1035 float f = (distAlong - curr.totalLength) / curr.lengthToNext;
1036 if (f < 0) f = 0;
1037 if (f > 1) f = 1;
1038 return Misc.interpolate(curr.fader.getBrightness() * curr.bMult,
1039 next.fader.getBrightness() * next.bMult, f);
1040 } else {
1041 return 0f;
1042 }
1043 }
1044 return 0f;
1045 }
1046
1047 protected transient SlipstreamBuilder builder = null;
1049 return builder;
1050 }
1051
1053 this.builder = builder;
1054 }
1055
1056 public SlipstreamParams2 getParams() {
1057 return params;
1058 }
1059
1060 public void render(CampaignEngineLayers layer, ViewportAPI viewport) {
1061 //if (true) return;
1063 if (lengthToIndexMap == null) return;
1064
1065 float bMult = getAbyssalBMult(false);
1066 if (bMult <= 0f) return;
1067
1068 if (false && builder != null) {
1069// CampaignFleetAPI pf = Global.getSector().getPlayerFleet();
1070// Vector2f loc = new Vector2f(pf.getLocation());
1071// Vector2f loc = new Vector2f(segments.get(0).loc);
1072// loc.x -= 500f;
1073// loc.y -= 300f;
1074// long seed = 23895464576452L + 4384357483229348234L;
1075// seed = 1181783497276652981L ^ seed;
1076// Random random = new Random(seed);
1077
1078// SlipstreamBuilder builder = new SlipstreamBuilder(loc, params, random);
1079// builder.buildTest();
1080 builder.renderDebug(1f);
1081 return;
1082 }
1083
1084
1085 if (true && false) {
1086 //BoundingBox box = BoundingBox.create(segments);
1087 float mx = Mouse.getX();
1088 float my = Mouse.getY();
1091 boolean inside = false;
1092 for (BoundingBox box : bounds) {
1093 box.renderDebug(1f);
1094 inside |= box.pointNeedsDetailedCheck(new Vector2f(wmx, wmy));
1095 }
1096
1097 GL11.glDisable(GL11.GL_TEXTURE_2D);
1098 GL11.glEnable(GL11.GL_BLEND);
1099 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1100
1101 GL11.glPointSize(20f);
1102 GL11.glEnable(GL11.GL_POINT_SMOOTH);
1103 if (inside) {
1104 Misc.setColor(Color.green);
1105 } else {
1106 Misc.setColor(Color.gray);
1107 }
1108
1109 GL11.glBegin(GL11.GL_POINTS);
1110 GL11.glVertex2f(wmx, wmy);
1111 GL11.glEnd();
1112 //return;
1113 }
1114
1115
1116
1117
1118 float viewRadius = new Vector2f(viewport.getVisibleWidth() * 0.5f, viewport.getVisibleHeight() * 0.5f).length();
1119 viewRadius += 500f;
1120
1121// viewRadius *= 0.5f;
1122// viewRadius = 500f;
1123
1124 List<SlipstreamSegment> near = getSegmentsNear(viewport.getCenter(), viewRadius);
1125 Set<SlipstreamSegment> nearSet = new LinkedHashSet<SlipstreamSegment>(near);
1126
1127 List<List<SlipstreamSegment>> subsections = new ArrayList<List<SlipstreamSegment>>();
1128 int prevIndex = -10;
1129 List<SlipstreamSegment> subsection = new ArrayList<SlipstreamSegment>();
1130 for (SlipstreamSegment seg : near) {
1131 if (prevIndex != seg.index - 1) {
1132 if (subsection != null && !subsection.isEmpty()) {
1133 subsections.add(subsection);
1134 }
1135 subsection = new ArrayList<SlipstreamSegment>();
1136 }
1137 subsection.add(seg);
1138 prevIndex = seg.index;
1139 }
1140 if (subsection != null && !subsection.isEmpty()) {
1141 subsections.add(subsection);
1142 }
1143
1144 SpriteAPI sprite0 = Global.getSettings().getSprite("misc", params.spriteKey1);
1145 sprite0.setNormalBlend();
1146 sprite0.setColor(params.spriteColor);
1147 SpriteAPI sprite1 = Global.getSettings().getSprite("misc", params.spriteKey2);
1148 sprite1.setNormalBlend();
1149 sprite1.setColor(params.spriteColor);
1150 SpriteAPI sprite2 = Global.getSettings().getSprite("misc", params.spriteKey3);
1151 sprite2.setNormalBlend();
1152 sprite2.setColor(params.spriteColor);
1153
1154 SpriteAPI edge = Global.getSettings().getSprite("misc", params.edgeKey);
1155 edge.setNormalBlend();
1156 edge.setColor(params.edgeColor);
1157
1158 //sprite.setColor(Misc.setAlpha(params.spriteColor1, 255));
1159 //sprite.setColor(Color.blue);
1160 for (List<SlipstreamSegment> subsection2 : subsections) {
1161 renderSegments(sprite0, sprite1, sprite2, edge, viewport.getAlphaMult(), subsection2, 0f, false);
1162 }
1163
1164 //sprite.setColor(Color.red);
1165 //renderLayer(sprite, texProgress2, viewport.getAlphaMult());
1166 //sprite.setColor(Color.green);
1167 //renderLayer(sprite, texProgress3, viewport.getAlphaMult());
1168
1169// int state = 0;
1170// for (int i = 0; i < segments.size() - 4; i += 2) {
1171// //GL11.glBegin(GL11.GL_POINTS);
1172// SlipstreamSegment prev = null;
1173// if (i > 0) {
1174// prev = segments.get(i - 1);
1175// }
1176// SlipstreamSegment curr = segments.get(i);
1177// SlipstreamSegment next = segments.get(i + 1);
1178// SlipstreamSegment next2 = segments.get(i + 2);
1179// SlipstreamSegment next3 = segments.get(i + 3);
1180// Vector2f p0 = curr.loc;
1181// Vector2f p1 = next.loc;
1182// Vector2f p2 = next2.loc;
1183// Vector2f p3 = next3.loc;
1184//
1185// if (state == 0) {
1186// state = 1;
1187// float p1ToP2 = Misc.getAngleInDegrees(p1, p2);
1188// float p2ToP3 = Misc.getAngleInDegrees(p2, p3);
1189// float diff = Misc.getAngleDiff(p1ToP2, p2ToP3);
1190// float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * diff * 0.5f + 180f;
1191// angle = Misc.getAngleInDegrees(p3, p2);
1192// float dist = Misc.getDistance(p2, p1);
1193// Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle);
1194// p1Adjusted.scale(dist);
1195// Vector2f.add(p1Adjusted, p2, p1Adjusted);
1196// curr.locB.set(p1Adjusted);
1197// } else if (state == 1) {
1198// curr.locB.set(curr.loc);
1199// } else if (state == 2) {
1200//
1201// }
1202// }
1203
1204
1205
1206
1207
1208 GL11.glDisable(GL11.GL_TEXTURE_2D);
1209 GL11.glEnable(GL11.GL_BLEND);
1210 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1211
1212 float zoom = Global.getSector().getViewport().getViewMult();
1213
1214 //GL11.glLineWidth(2f);
1215 //GL11.glLineWidth(Math.max(1f, 2f/zoom));
1216 GL11.glLineWidth(Math.max(1f, Math.min(2f, 2f/zoom)));
1217 //GL11.glLineWidth(1.5f);
1218 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1219
1220 Misc.setColor(new Color(1f, 1f, 1f, 0.5f));
1221 Misc.setColor(Color.white);
1222 //GL11.glLineWidth(1f);
1223
1224// for (SlipstreamSegment seg : segments) {
1225// if (seg.totalLength <= 0f && segments.indexOf(seg) > 1) {
1226// System.out.println("efwefwefwefe");
1227// }
1228// }
1229
1230 // draw bezier lines for debug
1231 for (float offset = -1f; false && offset <= 1f; offset += 0.1f) {
1232 //for (float offset = 0f; offset <= 0f; offset += 0.1f) {
1233 GL11.glBegin(GL11.GL_LINE_STRIP);
1234 float incr = 10f;
1235 for (float len = 0; len < totalLength; len += incr) {
1236// if (len > 10000f) {
1237// System.out.println("ewfwefew");
1238// }
1239 /*
1240 SlipstreamSegment curr = getSegmentForDist(len);
1241 if (curr == null) continue;
1242 int index = curr.index;
1243 if (index >= segments.size() - 2) continue;
1244 SlipstreamSegment next = segments.get(index + 1);
1245 SlipstreamSegment next2 = segments.get(index + 2);
1246
1247 if (index % 2 != 0) {
1248 curr = segments.get(index - 1);
1249 next = segments.get(index);
1250 next2 = segments.get(index + 1);
1251 }
1252
1253 float lenForT = len - curr.totalLength;
1254 float t = lenForT / (curr.lengthToNext + next.lengthToNext);
1255
1256 //Vector2f p = Misc.bezier(curr.loc, next.loc, next2.loc, t);
1257 Vector2f p0 = curr.loc;
1258 Vector2f p1 = next.loc;
1259 Vector2f p2 = next2.loc;
1260
1261 p0 = new Vector2f(p0);
1262 p0.x += curr.normal.x * params.width * 0.5f * offset;
1263 p0.y += curr.normal.y * params.width * 0.5f * offset;
1264
1265 p2 = new Vector2f(p2);
1266 p2.x += next2.normal.x * params.width * 0.5f * offset;
1267 p2.y += next2.normal.y * params.width * 0.5f * offset;
1268
1269 p1 = new Vector2f(next.locB);
1270 p1 = new Vector2f(p1);
1271 p1.x += next.normal.x * params.width * 0.5f * offset;
1272 p1.y += next.normal.y * params.width * 0.5f * offset;
1273
1274 Vector2f p = Misc.bezier(p0, p1, p2, t);
1275
1276// float tPrev = (prev.lengthToNext + len) / (prev.lengthToNext + curr.lengthToNext);
1277// Vector2f pPrev = Misc.bezier(prev.loc, curr.loc, next.loc, tPrev);
1278 //curr.lengthToNext + next.lengthToNext
1279// float f = lenForT / curr.lengthToNext;
1280// Vector2f perp;
1281// if (f < 1f) {
1282// perp = Misc.interpolateVector(curr.normal, next.normal, f);
1283// } else {
1284// f = (lenForT - curr.lengthToNext) / next.lengthToNext;
1288// perp = Misc.interpolateVector(next.normal, next2.normal, f);
1289// }
1290// perp.scale(offset * params.width * 0.5f);
1291 //perp.set(0, 0);
1292
1293 //p = Misc.interpolateVector(pPrev, p, 0.5f);
1294 //GL11.glVertex2f(p.x + perp.x, p.y + perp.y);
1295 *
1296 */
1297
1298 Vector2f p = getPointAt(len, offset);
1299 if (p != null) {
1300 GL11.glVertex2f(p.x, p.y);
1301 }
1302 }
1303 if (false) {
1304 Misc.setColor(Color.red);
1305 for (int i = 0; i < segments.size() - 3; i+=2) {
1306 //GL11.glBegin(GL11.GL_POINTS);
1307 SlipstreamSegment prev = null;
1308 if (i > 0) {
1309 prev = segments.get(i - 1);
1310 }
1311 SlipstreamSegment curr = segments.get(i);
1312 SlipstreamSegment next = segments.get(i + 1);
1313 SlipstreamSegment next2 = segments.get(i + 2);
1314 SlipstreamSegment next3 = segments.get(i + 3);
1315
1316 // GL11.glVertex2f(curr.loc.x, curr.loc.y);
1317 // GL11.glVertex2f(next.loc.x, next.loc.y);
1318 // GL11.glVertex2f(next2.loc.x, next2.loc.y);
1319
1320 Vector2f p0 = curr.loc;
1321 Vector2f p1 = next.loc;
1322 Vector2f p2 = next2.loc;
1323 Vector2f p3 = next3.loc;
1324
1325 // float p1ToP2 = Misc.getAngleInDegrees(p1, p2);
1326 // float p2ToP3 = Misc.getAngleInDegrees(p2, p3);
1327 // float diff = Misc.getAngleDiff(p1ToP2, p2ToP3);
1328 // float adjustment = Math.min(diff, Math.max(diff * 0.25f, diff - 10f));
1329 // adjustment = diff * 0.5f;
1330 // //adjustment = diff * 0.25f;
1331 // float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * adjustment * 1f + 180f;
1332 // //angle = Misc.getAngleInDegrees(p3, p2);
1333 // float dist = Misc.getDistance(p2, p1);
1334 // Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle);
1335 // p1Adjusted.scale(dist);
1336 // Vector2f.add(p1Adjusted, p2, p1Adjusted);
1337
1338 //GL11.glVertex2f(p1Adjusted.x, p1Adjusted.y);
1339 //GL11.glVertex2f(p1.x, p1.y);
1340
1341 p0 = new Vector2f(p0);
1342 p0.x += curr.normal.x * curr.width * 0.5f * offset;
1343 p0.y += curr.normal.y * curr.width * 0.5f * offset;
1344
1345 p2 = new Vector2f(p2);
1346 p2.x += next2.normal.x * next2.width * 0.5f * offset;
1347 p2.y += next2.normal.y * next2.width * 0.5f * offset;
1348
1349 p1 = new Vector2f(next.locB);
1350 p1 = new Vector2f(p1);
1351 p1.x += next.normal.x * next.width * 0.5f * offset;
1352 p1.y += next.normal.y * next.width * 0.5f * offset;
1353
1354 // p1ToP2 = Misc.getAngleInDegrees(p1, p2);
1355 // p2ToP3 = Misc.getAngleInDegrees(p2, p3);
1356 // diff = Misc.getAngleDiff(p1ToP2, p2ToP3);
1357 // adjustment = Math.min(diff, Math.max(diff * 0.25f, diff - 10f));
1358 // adjustment = diff * 0.5f;
1359 // //adjustment = diff * 0.25f;
1360 // angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * adjustment * 1f + 180f;
1361 // //angle = Misc.getAngleInDegrees(p3, p2);
1362 // dist = Misc.getDistance(p2, p1);
1363 // p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle);
1364 // p1Adjusted.scale(dist);
1365 // Vector2f.add(p1Adjusted, p2, p1Adjusted);
1366
1367 incr = 10f;
1368 for (float len = 0; len < curr.lengthToNext + next.lengthToNext; len += incr) {
1369 float t = len / (curr.lengthToNext + next.lengthToNext);
1370 //Vector2f p = Misc.bezier(curr.loc, next.loc, next2.loc, t);
1371 Vector2f p = Misc.bezier(p0, p1, p2, t);
1372
1373 // float tPrev = (prev.lengthToNext + len) / (prev.lengthToNext + curr.lengthToNext);
1374 // Vector2f pPrev = Misc.bezier(prev.loc, curr.loc, next.loc, tPrev);
1375
1376 float f = len / curr.lengthToNext;
1377 Vector2f perp;
1378 if (f < 1f) {
1379 perp = Misc.interpolateVector(curr.normal, next.normal, f);
1380 } else {
1381 f = (len - curr.lengthToNext) / next.lengthToNext;
1382 perp = Misc.interpolateVector(next.normal, next2.normal, f);
1383 }
1384 perp.scale(offset * curr.width * 0.5f);
1385 perp.set(0, 0);
1386
1387 //p = Misc.interpolateVector(pPrev, p, 0.5f);
1388 GL11.glVertex2f(p.x, p.y);
1389 //GL11.glVertex2f(p.x + perp.x, p.y + perp.y);
1390 //GL11.glVertex2f(pPrev.x, pPrev.y);
1391 }
1392 //if (i == 4) break;
1393 }
1394 }
1395 GL11.glEnd();
1396 }
1397
1398// GL11.glBegin(GL11.GL_LINES);
1399// for (int i = 0; i < segments.size() - 4; i+=2) {
1400// //GL11.glBegin(GL11.GL_POINTS);
1401// SlipstreamSegment prev = null;
1402// if (i > 0) {
1403// prev = segments.get(i - 1);
1404// }
1405// SlipstreamSegment curr = segments.get(i);
1406// SlipstreamSegment next = segments.get(i + 1);
1407// SlipstreamSegment next2 = segments.get(i + 2);
1408// SlipstreamSegment next3 = segments.get(i + 3);
1409//
1413//
1414// Vector2f p0 = curr.loc;
1415// Vector2f p1 = next.loc;
1416// Vector2f p2 = next2.loc;
1417// Vector2f p3 = next3.loc;
1418//
1419// float p1ToP2 = Misc.getAngleInDegrees(p1, p2);
1420// float p2ToP3 = Misc.getAngleInDegrees(p2, p3);
1421// float diff = Misc.getAngleDiff(p1ToP2, p2ToP3);
1422// float adjustment = Math.min(diff, Math.max(diff * 0.25f, diff - 10f));
1423// adjustment = diff * 0.5f;
1424// //adjustment = diff * 0.25f;
1425// float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * adjustment * 1f + 180f;
1426// //angle = Misc.getAngleInDegrees(p3, p2);
1427// float dist = Misc.getDistance(p2, p1);
1428// Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle);
1429// p1Adjusted.scale(dist);
1430// Vector2f.add(p1Adjusted, p2, p1Adjusted);
1431//
1432// //skip = diff < 30f;
1433// skip = false;
1434// if (skip) p1Adjusted.set(p1);
1435// skip = !skip;
1436//
1437// prevAdjustedP1 = p1Adjusted;
1438// //GL11.glVertex2f(p1Adjusted.x, p1Adjusted.y);
1439// //GL11.glVertex2f(p1.x, p1.y);
1440//
1441// float incr = 10f;
1442// Misc.setColor(new Color(1f, 0.5f, 0f, 1f));
1443// for (float len = 0; len < curr.lengthToNext + next.lengthToNext; len += incr) {
1444// float t = len / (curr.lengthToNext + next.lengthToNext);
1445// //Vector2f p = Misc.bezier(curr.loc, next.loc, next2.loc, t);
1446// Vector2f p = Misc.bezier(curr.loc, p1Adjusted, next2.loc, t);
1449//
1450// float f = len / curr.lengthToNext;
1451// Vector2f perp;
1452// if (f < 1f) {
1453// perp = Misc.interpolateVector(curr.normal, next.normal, f);
1454// } else {
1455// f = (len - curr.lengthToNext) / next.lengthToNext;
1456// perp = Misc.interpolateVector(next.normal, next2.normal, f);
1457// }
1458//
1459//
1460// perp.scale(1f * params.width * 0.5f);
1461//
1462// //p = Misc.interpolateVector(pPrev, p, 0.5f);
1463// //GL11.glVertex2f(p.x, p.y);
1464// GL11.glVertex2f(p.x + perp.x, p.y + perp.y);
1465// GL11.glVertex2f(p.x - perp.x, p.y - perp.y);
1466// //GL11.glVertex2f(pPrev.x, pPrev.y);
1467// }
1468// //if (i == 4) break;
1469// }
1470// GL11.glEnd();
1471
1472// GL11.glPointSize(10);
1473// GL11.glBegin(GL11.GL_POINTS);
1474// for (int i = 0; i < segments.size() - 4; i+=2) {
1475// if (i % 4 == 0) {
1476// Misc.setColor(Color.red);
1477// } else {
1478// Misc.setColor(Color.green);
1479// }
1480// //GL11.glBegin(GL11.GL_POINTS);
1481// //SlipstreamSegment prev = segments.get(i);
1482// SlipstreamSegment curr = segments.get(i);
1483// SlipstreamSegment next = segments.get(i + 1);
1484// SlipstreamSegment next2 = segments.get(i + 2);
1485// SlipstreamSegment next3 = segments.get(i + 3);
1486//
1490//
1491// Vector2f p0 = curr.loc;
1492// Vector2f p1 = next.loc;
1493// Vector2f p2 = next2.loc;
1494// Vector2f p3 = next3.loc;
1495//
1496// float p1ToP2 = Misc.getAngleInDegrees(p1, p2);
1497// float p2ToP3 = Misc.getAngleInDegrees(p2, p3);
1498// float diff = Misc.getAngleDiff(p1ToP2, p2ToP3);
1499// float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * diff * 1f + 180f;
1500// //angle = Misc.getAngleInDegrees(p3, p2);
1501// float dist = Misc.getDistance(p2, p1);
1502// Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle);
1503// p1Adjusted.scale(dist);
1504// Vector2f.add(p1Adjusted, p2, p1Adjusted);
1505// prevAdjustedP1 = p1Adjusted;
1506// //GL11.glVertex2f(p1Adjusted.x, p1Adjusted.y);
1507// //GL11.glVertex2f(p1.x, p1.y);
1508//
1509// GL11.glVertex2f(p0.x, p0.y);
1510// GL11.glVertex2f(p1Adjusted.x, p1Adjusted.y);
1511// GL11.glVertex2f(p2.x, p2.y);
1512// }
1513// GL11.glEnd();
1514
1515 if (false) {
1517 if (place != null) {
1518 Misc.setColor(Color.red);
1519 GL11.glPointSize(40f/zoom);
1520 GL11.glEnable(GL11.GL_POINT_SMOOTH);
1521 GL11.glBegin(GL11.GL_POINTS);
1522 Vector2f p = getPointAt(place[0], place[1]);
1523
1524 GL11.glVertex2f(p.x, p.y);
1525
1526 Misc.setColor(Color.blue);
1528 GL11.glVertex2f(p.x, p.y);
1529
1530 SlipstreamSegment seg = getSegmentForDist(place[0]);
1531 if (seg != null) {
1532 float withinSeg = place[0] - seg.totalLength;
1533 Vector2f p2 = new Vector2f(seg.normal.y, -seg.normal.x);
1534 p2.scale(withinSeg);
1535 Vector2f.add(p2, seg.loc, p2);
1536 float width = seg.wobbledWidth;
1537 if (segments.size() > seg.index + 1) {
1538 SlipstreamSegment next = segments.get(seg.index + 1);
1539 width = Misc.interpolate(seg.wobbledWidth, next.wobbledWidth,
1540 (place[0] - seg.totalLength) / seg.lengthToNext);
1541 }
1542 p2.x += getNormalAt(place[0]).x * place[1] * width * 0.5f;
1543 p2.y += getNormalAt(place[0]).y * place[1] * width * 0.5f;
1544 Misc.setColor(Color.green);
1545 GL11.glVertex2f(p2.x, p2.y);
1546 }
1547 GL11.glEnd();
1548 }
1549 }
1550
1551// GL11.glBegin(GL11.GL_LINE_STRIP);
1552// for (int i = 1; i < segments.size() - 2; i++) {
1553// SlipstreamSegment prev = segments.get(i);
1554// SlipstreamSegment curr = segments.get(i);
1555// SlipstreamSegment next = segments.get(i + 1);
1556// SlipstreamSegment next2 = segments.get(i + 2);
1557//
1558// float incr = 5f;
1559// for (float len = 0; len < curr.lengthToNext; len += incr) {
1560// float t = len / (curr.lengthToNext + next.lengthToNext);
1561// Vector2f p = Misc.bezier(curr.loc, next.loc, next2.loc, t);
1562//
1563// float tPrev = (prev.lengthToNext + len) / (prev.lengthToNext + curr.lengthToNext);
1564// Vector2f pPrev = Misc.bezier(prev.loc, curr.loc, next.loc, tPrev);
1565//
1566// //p = Misc.interpolateVector(pPrev, p, 0.5f);
1567// //GL11.glVertex2f(p.x, p.y);
1568// GL11.glVertex2f(pPrev.x, pPrev.y);
1569// }
1570// if (i == 4) break;
1571// }
1572// GL11.glEnd();
1573
1574 //if (true) return;
1575 boolean curvedTrails = true;
1576 boolean useTex = false;
1577 useTex = !Global.getSettings().getBoolean("slipstreamUseGLLines");
1578 //if (zoom > 1.25f) useTex = false;
1579 //useTex = true;
1580 //System.out.println("USETEX = " + useTex);
1581 if (!useTex) {
1582 GL11.glDisable(GL11.GL_TEXTURE_2D);
1583 GL11.glEnable(GL11.GL_BLEND);
1584 GL11.glLineWidth(Math.max(1f, Math.min(2f, 2f/zoom)));
1585 //GL11.glLineWidth(25f);
1586 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1587 GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST);
1588 }
1589
1590 //curvedTrails = false;
1591 if (!curvedTrails) {
1592 GL11.glBegin(GL11.GL_LINES);
1593 }
1594// GL11.glEnable(GL11.GL_POINT_SMOOTH);
1595// GL11.glPointSize(10f);
1596// GL11.glBegin(GL11.GL_POINTS);
1597 //int index = 0;
1598
1599 if (useTex) {
1600 GL11.glEnable(GL11.GL_TEXTURE_2D);
1601 GL11.glEnable(GL11.GL_BLEND);
1602 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1603
1604 SpriteAPI line = Global.getSettings().getSprite("graphics/hud/line4x4.png");
1605 //line = Global.getSettings().getSprite("graphics/hud/line32x32.png");
1606 line.bindTexture();
1607 } else {
1608 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1609 }
1610
1611 for (SlipstreamParticle p : particles) {
1612 SlipstreamSegment seg = getSegmentForDist(p.dist);
1613 if (seg == null || !nearSet.contains(seg)) continue;
1614
1615// index++;
1616// if (index > 1) break;
1617 //if (true) break;
1618 float a = viewport.getAlphaMult();
1619 if (p.remaining <= 0.5f) {
1620 a = p.remaining / 0.5f;
1621 } else if (p.elapsed < params.particleFadeInTime) {
1622 a = p.elapsed / params.particleFadeInTime;
1623 }
1624
1625 a *= getFaderBrightness(p.dist);
1626 a *= bMult;
1627
1628 //a *= 0.5f;
1629 //a *= 0.1f;
1630
1631 //a = 1f;
1632
1633// SlipstreamSegment seg = getSegmentForDist(p.dist);
1634// if (seg == null) continue;
1635 float yPos = p.yPos;
1636 //yPos = 0f;
1637
1638 if (curvedTrails) {
1639 if (useTex) {
1640 GL11.glBegin(GL11.GL_QUAD_STRIP);
1641 Vector2f curr = getPointAt(p.dist, yPos);
1642 if (curr == null || !viewport.isNearViewport(curr, p.speed * params.lineLengthFractionOfSpeed + 50f)) {
1643 GL11.glEnd();
1644 continue;
1645 }
1646 float iter = 5f;
1647 float incr = p.speed * params.lineLengthFractionOfSpeed / iter;
1648 float lw = 1f;
1649 for (float i = 0; i < iter; i++) {
1650 float min = incr * 1f;
1651 float dist = p.dist - i * incr - min;
1652 Vector2f next = getPointAt(dist, yPos);
1653 if (next == null) break;
1654
1655 Vector2f perp = getNormalAt(dist);
1656 if (perp == null) {
1657 GL11.glEnd();
1658 break;
1659 }
1660
1661 float a1 = a * (iter - i) / (iter - 1);
1662 if (i == 0) a1 = 0f;
1663
1664 Misc.setColor(p.color, a1);
1665 GL11.glTexCoord2f(0, 0f);
1666 GL11.glVertex2f(curr.x + perp.x * lw, curr.y + perp.y * lw);
1667 GL11.glTexCoord2f(0, 1f);
1668 GL11.glVertex2f(curr.x - perp.x * lw, curr.y - perp.y * lw);
1669 curr = next;
1670 }
1671 GL11.glEnd();
1672 } else {
1673 GL11.glBegin(GL11.GL_LINE_STRIP);
1674 //GL11.glBegin(GL11.GL_LINES);
1675 Vector2f curr = getPointAt(p.dist, yPos);
1676 if (curr == null || !viewport.isNearViewport(curr, p.speed * params.lineLengthFractionOfSpeed + 50f)) {
1677 GL11.glEnd();
1678 continue;
1679 }
1680 float iter = 5f;
1681 float incr = p.speed * params.lineLengthFractionOfSpeed / iter;
1682 for (float i = 0; i < iter; i++) {
1683
1684 float min = incr * 0.5f;
1685 Vector2f next = getPointAt(p.dist - i * incr - min, yPos);
1686 if (next == null) {
1687 GL11.glEnd();
1688 break;
1689 }
1690
1691 float a1 = a * (iter - i) / (iter - 1);
1692 //float a2 = a * (iter - i - 1) / (iter - 1);
1693 if (i == 0) a1 = 0f;
1694
1695 Misc.setColor(p.color, a1);
1696 GL11.glVertex2f(curr.x, curr.y);
1697 //Misc.setColor(p.color, a2);
1698 //GL11.glVertex2f(next.x, next.y);
1699 curr = next;
1700 }
1701 GL11.glEnd();
1702 }
1703 } else {
1704 Vector2f start = getPointAt(p.dist + p.speed * params.lineLengthFractionOfSpeed * 0.1f, yPos);
1705 if (start == null || !viewport.isNearViewport(start, 500)) continue;
1706
1707 Vector2f mid = getPointAt(p.dist, yPos);
1708 if (mid == null) continue;
1709 Vector2f end = getPointAt(p.dist - p.speed * params.lineLengthFractionOfSpeed * 0.9f, yPos);
1710 if (end == null) continue;
1711
1712 Misc.setColor(p.color, 0f);
1713 GL11.glVertex2f(start.x, start.y);
1714 Misc.setColor(p.color, a);
1715 GL11.glVertex2f(mid.x, mid.y);
1716 GL11.glVertex2f(mid.x, mid.y);
1717 Misc.setColor(p.color, 0f);
1718 GL11.glVertex2f(end.x, end.y);
1719 }
1720//
1721 }
1722 if (!curvedTrails) {
1723 GL11.glEnd();
1724 }
1725 }
1726
1727
1728// public void renderSegments(SpriteAPI sprite, SpriteAPI edge, float alpha, List<SlipstreamSegment> segments) {
1729// renderSegments(sprite, edge, alpha, segments, 0f);
1730// }
1731
1732 public float getAbyssalBMult(boolean forMap) {
1733 if (forMap) return 1f;
1735 float bMult = 1f;
1736 if (!forMap) {
1738 if (playerFleet != null) {
1739 float depth = Misc.getAbyssalDepth(playerFleet);
1740 if (depth > 0) {
1741 bMult = Math.max(0f, 1f - depth);
1742 }
1743 }
1744 }
1745 return bMult;
1746 }
1747
1748 public void renderSegments(SpriteAPI sprite0, SpriteAPI sprite1, SpriteAPI sprite2,
1749 SpriteAPI edge, float alpha, List<SlipstreamSegment> segments, float extraTX, boolean forMap) {
1750 //if (true) return;
1751
1752 float bMult = getAbyssalBMult(forMap);
1753 if (bMult <= 0f) return;
1754
1755
1756 GL11.glEnable(GL11.GL_TEXTURE_2D);
1757 GL11.glEnable(GL11.GL_BLEND);
1758 //GL11.glDisable(GL11.GL_BLEND);
1759 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1760 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1761
1762 //color = Misc.interpolateColor(color, Color.black, 0.5f);
1763 //color = Color.black;
1764 //color = Misc.scaleColorOnly(color, 0.25f);
1765 //color = Misc.setAlpha(color, 100);
1766
1767 boolean wireframe = false;
1768 //wireframe = true;
1769 if (wireframe) {
1770 GL11.glLineWidth(1f);
1771 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1772 GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
1773 GL11.glDisable(GL11.GL_TEXTURE_2D);
1774 GL11.glDisable(GL11.GL_BLEND);
1775
1776 Misc.setColor(Color.yellow);
1777 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1778 //GL11.glLineWidth(3f);
1779 GL11.glBegin(GL11.GL_LINE_STRIP);
1780 for (SlipstreamSegment curr : segments) {
1781 GL11.glVertex2f(curr.loc.x, curr.loc.y);
1782 }
1783 GL11.glEnd();
1784 }
1785
1786 boolean subtract = false;
1787 //subtract = true;
1788 if (subtract) {
1789 GL14.glBlendEquation(GL14.GL_FUNC_REVERSE_SUBTRACT);
1790 }
1791
1792 // main background
1793 if (!wireframe) {
1794 GL11.glEnable(GL11.GL_TEXTURE_2D);
1795 GL11.glEnable(GL11.GL_BLEND);
1796 }
1797 //GL11.glDisable(GL11.GL_BLEND);
1798 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1799 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1800
1801 if (!forMap) extraTX = texProgress0;
1802
1803 sprite0.bindTexture();
1804 Color color = sprite0.getColor();
1805 GL11.glBegin(GL11.GL_QUAD_STRIP);
1806 for (int i = 0; i < segments.size(); i++) {
1807 SlipstreamSegment curr = segments.get(i);
1808 float a = curr.fader.getBrightness() * curr.bMult * bMult;
1809 if (i == 0 || i == segments.size() - 1) a = 0f;
1810
1811 Vector2f p1 = new Vector2f(curr.loc);
1812 p1.x += curr.normal.x * curr.width * 0.5f;
1813 p1.y += curr.normal.y * curr.width * 0.5f;
1814 Vector2f p2 = new Vector2f(curr.loc);
1815 p2.x -= curr.normal.x * curr.width * 0.5f;
1816 p2.y -= curr.normal.y * curr.width * 0.5f;
1817
1818 if (!forMap) {
1819 p1.x += curr.wobble1.vector.x;
1820 p1.y += curr.wobble1.vector.y;
1821 p2.x += curr.wobble2.vector.x;
1822 p2.y += curr.wobble2.vector.y;
1823 }
1824
1825 Misc.setColor(color, alpha * 1f * a);
1826 GL11.glTexCoord2f(curr.tx + extraTX, 0f);
1827 GL11.glVertex2f(p1.x, p1.y);
1828 GL11.glTexCoord2f(curr.tx + extraTX, 1f);
1829 GL11.glVertex2f(p2.x, p2.y);
1830 }
1831 GL11.glEnd();
1832
1833 if (!forMap) {
1834 sprite1.bindTexture();
1835 color = sprite1.getColor();
1836 GL11.glBegin(GL11.GL_QUAD_STRIP);
1837 for (int i = 0; i < segments.size(); i++) {
1838 SlipstreamSegment curr = segments.get(i);
1839 float a = curr.fader.getBrightness() * curr.bMult * bMult;
1840 if (i == 0 || i == segments.size() - 1) a = 0f;
1841
1842 Vector2f p1 = new Vector2f(curr.loc);
1843 p1.x += curr.normal.x * curr.width * 0.5f;
1844 p1.y += curr.normal.y * curr.width * 0.5f;
1845 Vector2f p2 = new Vector2f(curr.loc);
1846 p2.x -= curr.normal.x * curr.width * 0.5f;
1847 p2.y -= curr.normal.y * curr.width * 0.5f;
1848
1849 p1.x += curr.wobble1.vector.x;
1850 p1.y += curr.wobble1.vector.y;
1851 p2.x += curr.wobble2.vector.x;
1852 p2.y += curr.wobble2.vector.y;
1853
1854 Misc.setColor(color, alpha * 1f * a);
1855 GL11.glTexCoord2f(curr.tx + texProgress1, 0f);
1856 GL11.glVertex2f(p1.x, p1.y);
1857 GL11.glTexCoord2f(curr.tx + texProgress1, 1f);
1858 GL11.glVertex2f(p2.x, p2.y);
1859 }
1860 GL11.glEnd();
1861
1862 sprite2.bindTexture();
1863 color = sprite2.getColor();
1864 GL11.glBegin(GL11.GL_QUAD_STRIP);
1865 for (int i = 0; i < segments.size(); i++) {
1866 SlipstreamSegment curr = segments.get(i);
1867 float a = curr.fader.getBrightness() * curr.bMult * bMult;
1868 if (i == 0 || i == segments.size() - 1) a = 0f;
1869
1870 Vector2f p1 = new Vector2f(curr.loc);
1871 p1.x += curr.normal.x * curr.width * 0.5f;
1872 p1.y += curr.normal.y * curr.width * 0.5f;
1873 Vector2f p2 = new Vector2f(curr.loc);
1874 p2.x -= curr.normal.x * curr.width * 0.5f;
1875 p2.y -= curr.normal.y * curr.width * 0.5f;
1876
1877 p1.x += curr.wobble1.vector.x;
1878 p1.y += curr.wobble1.vector.y;
1879 p2.x += curr.wobble2.vector.x;
1880 p2.y += curr.wobble2.vector.y;
1881
1882 Misc.setColor(color, alpha * 1f * a);
1883 GL11.glTexCoord2f(curr.tx + texProgress2, 0f);
1884 GL11.glVertex2f(p1.x, p1.y);
1885 GL11.glTexCoord2f(curr.tx + texProgress2, 1f);
1886 GL11.glVertex2f(p2.x, p2.y);
1887 }
1888 GL11.glEnd();
1889 }
1890
1891
1892 // edges
1893 color = edge.getColor();
1894 float wobbleMult = 0.5f;
1895 edge.bindTexture();
1896 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1897 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1898
1899 GL11.glBegin(GL11.GL_QUAD_STRIP);
1900
1901 for (int i = 0; i < segments.size(); i++) {
1902 SlipstreamSegment curr = segments.get(i);
1903 float a = curr.fader.getBrightness() * curr.bMult * bMult;
1904 if (i == 0 || i == segments.size() - 1) a = 0f;
1905
1906// float width = getWidth(curr.totalLength);
1907// float wobbled = getWobbledWidth(curr.totalLength);
1908// float yOff = width / wobbled;
1909// Vector2f p1 = getPointAt(curr.totalLength, yOff);
1910// Vector2f p2 = getPointAt(curr.totalLength, yOff);
1911// if (p1 == null) {
1912// System.out.println("efwefwefew");
1913// p1 = getPointAt(curr.totalLength, yOff);
1914// }
1915// p2 = new Vector2f(p1);
1916
1917 Vector2f p1 = new Vector2f(curr.loc);
1918 Vector2f p2 = new Vector2f(curr.loc);
1919 p1.x += curr.normal.x * curr.width * 0.5f;
1920 p1.y += curr.normal.y * curr.width * 0.5f;
1921 p2.x += curr.normal.x * (curr.width * 0.5f - params.edgeWidth);
1922 p2.y += curr.normal.y * (curr.width * 0.5f - params.edgeWidth);
1923
1924// p2.x += curr.normal.x * -params.edgeWidth;
1925// p2.y += curr.normal.y * -params.edgeWidth;
1926
1927 if (!forMap) {
1928 p1.x += curr.wobble1.vector.x * wobbleMult;
1929 p1.y += curr.wobble1.vector.y * wobbleMult;
1930 p2.x += curr.wobble1.vector.x * wobbleMult;
1931 p2.y += curr.wobble1.vector.y * wobbleMult;
1932 }
1933
1934 Misc.setColor(color, alpha * 1f * a);
1935 GL11.glTexCoord2f(curr.txe1, 1f);
1936 GL11.glVertex2f(p1.x, p1.y);
1937 GL11.glTexCoord2f(curr.txe1, 0f);
1938 GL11.glVertex2f(p2.x, p2.y);
1939 }
1940 GL11.glEnd();
1941
1942 //edge2.bindTexture();
1943 GL11.glBegin(GL11.GL_QUAD_STRIP);
1944
1945 for (int i = 0; i < segments.size(); i++) {
1946 SlipstreamSegment curr = segments.get(i);
1947 float a = curr.fader.getBrightness() * curr.bMult * bMult;
1948 if (i == 0 || i == segments.size() - 1) a = 0f;
1949
1950 Vector2f p1 = new Vector2f(curr.loc);
1951 p1.x -= curr.normal.x * curr.width * 0.5f;
1952 p1.y -= curr.normal.y * curr.width * 0.5f;
1953 Vector2f p2 = new Vector2f(curr.loc);
1954 p2.x -= curr.normal.x * (curr.width * 0.5f - params.edgeWidth);
1955 p2.y -= curr.normal.y * (curr.width * 0.5f - params.edgeWidth);
1956
1957 if (!forMap) {
1958 p1.x += curr.wobble2.vector.x * wobbleMult;
1959 p1.y += curr.wobble2.vector.y * wobbleMult;
1960 p2.x += curr.wobble2.vector.x * wobbleMult;
1961 p2.y += curr.wobble2.vector.y * wobbleMult;
1962 }
1963
1964 Misc.setColor(color, alpha * 1f * a);
1965 GL11.glTexCoord2f(curr.txe2, 1f);
1966 GL11.glVertex2f(p1.x, p1.y);
1967 GL11.glTexCoord2f(curr.txe2, 0f);
1968 GL11.glVertex2f(p2.x, p2.y);
1969 }
1970 GL11.glEnd();
1971
1972
1973 if (subtract) {
1974 GL14.glBlendEquation(GL14.GL_FUNC_ADD);
1975 }
1976
1977 if (wireframe) GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
1978 }
1979
1980
1981
1982
1983
1984 public Color getRandomColor() {
1985 return Misc.interpolateColor(params.minColor, params.maxColor, (float) Math.random());
1986 }
1987
1988 public float getTotalLength() {
1989 return totalLength;
1990 }
1991
1992
2002 public float [] getLengthAndWidthFractionWithinStream(Vector2f loc) {
2003 return getLengthAndWidthFractionWithinStream(loc, 0f, false, 0f);
2004 }
2005 public float [] getLengthAndWidthFractionWithinStream(Vector2f loc, float extraRangeForCheck, boolean allowOutsideStream, float extraWidthForSegments) {
2007
2008 float dist = Misc.getDistance(loc, entity.getLocation());
2009 if (dist > getRenderRange()) return null;
2010
2011 List<SlipstreamSegment> near = getSegmentsNear(loc, extraRangeForCheck);
2012
2013 for (SlipstreamSegment curr : near) {
2014 SlipstreamSegment next = null;
2015 if (segments.size() > curr.index + 1) {
2016 next = segments.get(curr.index + 1);
2017 } else {
2018 next = new SlipstreamSegment();
2019 //next2.width = next.width;
2020 next.wobbledWidth = curr.wobbledWidth;
2021
2022 next.normal = curr.normal;
2023 //next2.dir = next.dir;
2024 next.loc = new Vector2f(curr.dir);
2025 next.loc.scale(curr.lengthToPrev);
2026 Vector2f.add(next.loc, curr.loc, next.loc);
2027 //next2.locB = next2.loc;
2028 next.lengthToPrev = curr.lengthToPrev;
2029 //continue;
2030 }
2031
2032 Vector2f p3 = loc;
2033 Vector2f p1 = curr.loc;
2034 Vector2f p2 = next.loc;
2035
2036 Vector2f currNormalP1 = new Vector2f(curr.loc);
2037 Vector2f currNormalP2 = new Vector2f(curr.normal);
2038 currNormalP2.scale(100f);
2039 Vector2f.add(currNormalP2, currNormalP1, currNormalP2);
2040
2041 Vector2f nextNormalP1 = new Vector2f(next.loc);
2042 Vector2f nextNormalP2 = new Vector2f(next.normal);
2043 nextNormalP2.scale(100f);
2044 Vector2f.add(nextNormalP2, nextNormalP1, nextNormalP2);
2045
2046 //Vector2f dir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p1, p2));
2047 Vector2f dir = new Vector2f(curr.dir);
2048 dir.scale(100f);
2049 Vector2f p4 = Vector2f.add(p3, dir, new Vector2f());
2050
2051 Vector2f currNormalP = Misc.intersectLines(currNormalP1, currNormalP2, p3, p4);
2052 if (currNormalP == null) continue;
2053 Vector2f nextNormalP = Misc.intersectLines(nextNormalP1, nextNormalP2, p3, p4);
2054 if (nextNormalP == null) continue;
2055
2056 float u = (p3.x - currNormalP.x) * (nextNormalP.x - currNormalP.x) +
2057 (p3.y - currNormalP.y) * (nextNormalP.y - currNormalP.y);
2058 float denom = Vector2f.sub(nextNormalP, currNormalP, new Vector2f()).length();
2059 denom *= denom;
2060 if (denom == 0) continue;
2061 u /= denom;
2062
2063 if (u >= 0 && u <= 1) { // p3 is between the two points on the normals
2064 Vector2f normalAtP3 = Misc.interpolateVector(curr.normal, next.normal, u);
2065 normalAtP3.scale(100f);
2066 Vector2f p3PlusNormal = Vector2f.add(p3, normalAtP3, new Vector2f());
2067
2068 Vector2f intersect = Misc.intersectLines(p1, p2, p3, p3PlusNormal);
2069 if (intersect == null) continue;
2070
2071 float distFromLine = Vector2f.sub(intersect, p3, new Vector2f()).length();
2072 float width = Misc.interpolate(curr.wobbledWidth, next.wobbledWidth, u);
2073 width += extraWidthForSegments;
2074 if (distFromLine >= width / 2f && !allowOutsideStream) return null;
2075
2076 float [] result = new float[2];
2077 //result[0] = curr.totalLength + u * curr.lengthToNext;
2078 result[0] = curr.totalLength + u * next.lengthToPrev;
2079 result[1] = distFromLine / (width / 2f);
2080
2081 float currToLoc = Misc.getAngleInDegrees(p1, p3);
2082 float segDir = Misc.getAngleInDegrees(p1, p2);
2083 if (Misc.getClosestTurnDirection(segDir, currToLoc) < 0) {
2084 result[1] = -result[1];
2085 }
2086
2087 return result;
2088 }
2089 }
2090 return null;
2091 }
2092
2093 public void applyEffectToEntities(float amount) {
2094 if (entity.getContainingLocation() == null) return;
2095
2096 float days = Global.getSector().getClock().convertToDays(amount);
2098 if (isPreventedFromAffecting(fleet)) continue;
2099 applyEffect(fleet, days);
2100 }
2101 //for (SectorEntityToken entity : entity.getContainingLocation().getEntitiesWithTag(Tags.GHOST)) {
2103 if (entity.hasTag(Tags.GHOST)) {
2104 if (isPreventedFromAffecting(entity)) continue;
2106 } else if (Entities.WRECK.equals(entity.getCustomEntityType())) {
2107 if (isPreventedFromAffecting(entity)) continue;
2109 }
2110
2111 }
2112 }
2113
2114 //protected boolean playerWasInSlipstream = false;
2116 protected float playerDesiredYOffset = 1000;
2124 public void applyEffect(SectorEntityToken other, float days) {
2125 if (other.hasTag(Tags.UNAFFECTED_BY_SLIPSTREAM)) return;
2126
2127 if (!containsPoint(other.getLocation(), 0f)) {
2128 if (other.isPlayerFleet()) {
2130 }
2131 return;
2132 }
2133
2134 if (other instanceof CampaignFleetAPI) {
2135 CampaignFleetAPI fleet = (CampaignFleetAPI) other;
2136
2137// if (fleet.isPlayerFleet()) {
2138// if (getLengthAndWidthFractionWithinStream(fleet.getLocation()) == null) {
2139// System.out.println("wefwefwefe");
2140// }
2141// System.out.println("efwefwef");
2142// }
2143
2144 float [] offset = getLengthAndWidthFractionWithinStream(fleet.getLocation());
2145 if (offset == null) {
2146 if (fleet.isPlayerFleet()) {
2148 }
2149 return;
2150 }
2151
2152// if (fleet.isPlayerFleet()) {
2153// System.out.println("Location in stream: " + offset[0] + ", " + offset[1]);
2154// }
2155
2156 //params.burnLevel = 10;
2157
2158 float distAlong = offset[0];
2159 float yOff = offset[1];
2160
2161// float intensity = 1f;
2162// if (Math.abs(yOff) > 0.5f) {
2163// intensity *= (1f - Math.abs(yOff)) / 0.5f;
2164// }
2165 float intensity = getIntensity(yOff);
2166 float wMult = getWidthBasedSpeedMult(distAlong);
2167 //System.out.println("wMult: " + wMult);
2168 intensity *= wMult;
2169 intensity *= getFaderBrightness(distAlong);
2170 //intensity *= intensity;
2171 //System.out.println(intensity);
2172
2173 if (intensity <= 0.05f) {
2174 if (fleet.isPlayerFleet()) {
2176 }
2177 return;
2178 }
2179
2183
2184 if (fleet.isPlayerFleet()) {
2185 //if (!playerWasInSlipstream) {
2186 // playerWasInSlipstream = true;
2188 String text = "Entering slipstream";
2189 if (params.enteringSlipstreamTextOverride != null) {
2190 text = params.enteringSlipstreamTextOverride;
2191 }
2192 float dur = 0.5f;
2193 if (params.enteringSlipstreamTextDurationOverride != null) {
2194 dur = params.enteringSlipstreamTextDurationOverride;
2195 }
2196 if (!text.isEmpty()) {
2197 fleet.addFloatingText(text, Misc.setAlpha(fleet.getIndicatorColor(), 255), dur);
2198 }
2199 }
2201 }
2202
2203 //System.out.println("Intensity: " + intensity);
2204
2205 // "wind" effect - adjust velocity
2206 float maxFleetBurn = fleet.getFleetData().getBurnLevel();
2207 float currFleetBurn = fleet.getCurrBurnLevel();
2208
2209 boolean reversePolarity = Misc.isReversePolarity(fleet);
2210
2211 float maxWindBurn = params.burnLevel * 2f;
2212 float currWindBurn = intensity * maxWindBurn;
2213 float maxFleetBurnIntoWind = maxFleetBurn - Math.abs(currWindBurn);
2214 float seconds = days * Global.getSector().getClock().getSecondsPerDay();
2215
2216
2217// float angle = Misc.getAngleInDegreesStrict(this.entity.getLocation(), fleet.getLocation()) + 180f;
2218// Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(angle);
2219 Vector2f p1 = getPointAt(distAlong, yOff);
2220 Vector2f p2 = getPointAt(distAlong + 1f, yOff);
2221 if (reversePolarity) {
2222 p1 = getPointAt(distAlong, yOff);
2223 p2 = getPointAt(distAlong - 1f, yOff);
2224 }
2225 if (p1 == null || p2 == null) {
2226 if (fleet.isPlayerFleet()) {
2228 }
2229 return;
2230 }
2231
2232
2233 //Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(entity.getFacing());
2234 Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p1, p2));
2235 if (currWindBurn < 0) {
2236 windDir.negate();
2237 }
2238
2239 Vector2f velDir = Misc.normalise(new Vector2f(fleet.getVelocity()));
2240 //float baseFleetAccel = Misc.getSpeedForBurnLevel(fleet.getFleetData().getMinBurnLevel());
2241 float baseFleetAccel = fleet.getTravelSpeed();
2242 if (baseFleetAccel < 10f) baseFleetAccel = 10f;
2243
2244 boolean fleetTryingToMove = fleet.getMoveDestination() != null &&
2245 Misc.getDistance(fleet.getLocation(), fleet.getMoveDestination()) > fleet.getRadius() + 10f;
2246 if (fleet.isPlayerFleet()) {
2247 fleetTryingToMove &= (
2248 Global.getSector().getCampaignUI().isPlayerFleetFollowingMouse() ||
2249 fleet.wasSlowMoving()
2250 );
2251
2252 String key = "$slipstream_moveToYOffset";
2253 if (fleetTryingToMove && fleet.getMoveDestination() != null) {
2254// float mx = Mouse.getX();
2255// float my = Mouse.getY();
2256 // this accounts for screen scaling
2257 float mx = Global.getSettings().getMouseX();
2258 float my = Global.getSettings().getMouseY();
2261 float [] desired = getLengthAndWidthFractionWithinStream(new Vector2f(wmx, wmy));
2262 if (desired != null) {
2263 playerDesiredYOffset = desired[1];
2264 fleet.getMemoryWithoutUpdate().set(key, true, 0.2f);
2265 } else {
2266 playerDesiredYOffset = 1000f;
2267 }
2268 }
2269 if (!fleet.getMemoryWithoutUpdate().getBoolean(key)) {
2270 playerDesiredYOffset = 1000f;
2271 }
2272 }
2273
2274 //System.out.println("PDY: " + playerDesiredYOffset);
2275 float windSpeedReduction = 0f;
2276 if (!fleetTryingToMove) {
2277 Vector2f dest = new Vector2f(windDir);
2278 dest.scale(1000f);
2280 float currOffset = offset[1];
2281 float diff = playerDesiredYOffset - currOffset;
2282 float sign = Math.signum(diff);
2283 if (reversePolarity) {
2284 sign = -sign;
2285 }
2286 float mult = Math.min(Math.abs(diff) * 1f, 1f);
2287 dest = Misc.rotateAroundOrigin(dest, Math.min(60f, 60f * mult * 1f) * sign);
2288 }
2289 Vector2f.add(dest, fleet.getLocation(), dest);
2290 fleet.setMoveDestination(dest.x, dest.y);
2291 } else {
2292 Vector2f moveDir = Misc.getUnitVectorAtDegreeAngle(
2294 float dot = Vector2f.dot(windDir, moveDir);
2295 if (fleet.wasSlowMoving()) dot = -1f;
2296 if (dot < 0) {
2297 float accelBasedMult = fleet.getAcceleration() / baseFleetAccel;
2298 accelBasedMult *= accelBasedMult;
2299 if (accelBasedMult > 1f) accelBasedMult = 1f;
2300 if (accelBasedMult < 0.1f) accelBasedMult = 0.1f;
2301 windSpeedReduction = -dot * fleet.getFleetData().getBurnLevel() * accelBasedMult;
2302 }
2303 }
2304
2305 //float burnBonus = fleet.getFleetData().getBurnLevel() - fleet.getFleetData().getMinBurnLevelUnmodified();
2306 float burnBonus = fleet.getFleetData().getBurnLevel() - fleet.getFleetData().getMinBurnLevel();
2307 if (burnBonus < 0) burnBonus = 0;
2308 //float maxSpeedWithWind = Misc.getSpeedForBurnLevel(params.burnLevel + burnBonus);
2309 float maxSpeedWithWind = Misc.getSpeedForBurnLevel((params.burnLevel * intensity) + burnBonus);
2310 if (windSpeedReduction > 0) {
2311 maxSpeedWithWind = Misc.getSpeedForBurnLevel(
2312 Math.max(params.burnLevel * 0.5f * intensity, params.burnLevel * intensity - windSpeedReduction));
2313 }
2314
2315 if (reversePolarity) {
2317 maxSpeedWithWind *= polarityMult;
2318 //System.out.println("MSWW: " + maxSpeedWithWind + ", mult: " + polarityMult);
2319 //maxSpeedWithWind *= ReversePolarity.SLIPSTREAM_SPEED_MULT;
2320 }
2321
2322 float fleetSpeedAlongWind = Vector2f.dot(windDir, fleet.getVelocity());
2323 if (fleetSpeedAlongWind >= maxSpeedWithWind) {
2324// float dotPlayerAndWindVel = Vector2f.dot(windDir, velDir);
2325// if (dotPlayerAndWindVel > 0.98f) {
2326 return;
2327 //}
2328 }
2329
2330 velDir.scale(currFleetBurn);
2331
2332 //float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir);
2333
2334
2335 float windSpeed = Misc.getSpeedForBurnLevel(currWindBurn);
2336 //float fleetSpeed = fleet.getTravelSpeed();
2337 Vector2f windVector = new Vector2f(windDir);
2338 windVector.scale(windSpeed);
2339
2340 Vector2f vel = fleet.getVelocity();
2341// Vector2f diff = Vector2f.sub(windVector, vel, new Vector2f());
2342// //windDir.scale(seconds * fleet.getAcceleration());
2343// float max = diff.length();
2344// diff = Misc.normalise(diff);
2345// //diff.scale(Math.max(windSpeed * seconds, fleet.getAcceleration() * 1f * seconds));
2346// diff.scale(fleet.getAcceleration() * 3f * seconds);
2347// //diff.scale(fleet.getTravelSpeed() * 5f * seconds);
2348// //diff.scale(accelMult);
2349// if (diff.length() > max) {
2350// diff.scale(max / diff.length());
2351// }
2352 //System.out.println("Applying diff: " + diff);
2353 //fleet.setVelocity(vel.x + diff.x, vel.y + diff.y);
2354
2355
2356// Vector2f velDir = Misc.normalise(new Vector2f(fleet.getVelocity()));
2357// velDir.scale(currFleetBurn);
2358//
2359// float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir);
2360 //System.out.println("fleetBurnAgainstWind: " + fleetBurnAgainstWind);
2361 float accelMult = 0.5f + 2f * intensity;
2362 accelMult += 0.25f * 20f * intensity;
2363// if (fleetBurnAgainstWind > maxFleetBurnIntoWind) {
2364// //accelMult += 0.75f + 0.25f * (fleetBurnAgainstWind - maxFleetBurnIntoWind);
2365// accelMult += 0.25f * (fleetBurnAgainstWind - maxFleetBurnIntoWind);
2366// } else {
2367// }
2368
2369 //if (fleetTryingToMove) accelMult *= 0.15f;
2370 //if (accelMult < 2f) accelMult = 2f;
2371 //wefwefwefew
2372
2373 //Vector2f vel = fleet.getVelocity();
2374 //windDir.scale(seconds * fleet.getAcceleration() * accelMult);
2375 //float baseFleetAccel = Math.max(fleet.getTravelSpeed(), fleet.getAcceleration());
2376
2377 float extraAccelMult = params.accelerationMult;
2378 windDir.scale(seconds * baseFleetAccel * accelMult * extraAccelMult);
2379
2380 if (extraAccelMult > 1f) {
2381 float windAccelAmountThisFrame = windDir.length();
2382 float maxAccelThisFrame = maxSpeedWithWind - fleetSpeedAlongWind;
2383
2384 if (windAccelAmountThisFrame > maxAccelThisFrame) {
2385 float accelThisFrameMult = maxAccelThisFrame / Math.max(1f, windAccelAmountThisFrame);
2386 if (accelThisFrameMult > 1f) accelThisFrameMult = 1f;
2387 windDir.scale(accelThisFrameMult);
2388 }
2389 }
2390
2391 fleet.setVelocity(vel.x + windDir.x, vel.y + windDir.y);
2392
2393 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_1",
2396 //fleet.getStats().getFuelUseHyperMult());
2397
2398
2399 boolean withGlow = true;
2400 withGlow = !params.forceNoWindVisualEffectOnFleets;
2401 //withGlow = false;
2402 if (withGlow) {
2403 Color glowColor = params.windGlowColor;
2406 }
2407
2408 int alpha = glowColor.getAlpha();
2409 if (alpha < 75) {
2410 glowColor = Misc.setAlpha(glowColor, 75);
2411 }
2412 // visual effects - glow, tail
2413
2414 p1 = getNoWobblePointAt(distAlong, yOff);
2415 p2 = getNoWobblePointAt(distAlong + 100f, yOff);
2416 if (reversePolarity) {
2417 p1 = getNoWobblePointAt(distAlong, yOff);
2418 p2 = getNoWobblePointAt(distAlong - 100f, yOff);
2419 }
2420 if (p1 != null && p2 != null) {
2422
2423// float fleetSpeedAlongWind = Vector2f.dot(windDir, fleet.getVelocity());
2424// //float fleetSpeed = fleet.getVelocity().length();
2425//
2426// windSpeed = Misc.getSpeedForBurnLevel(params.burnLevel);
2427// float matchingWindFraction = fleetSpeedAlongWind/windSpeed;
2428// float effectMag = 1f - matchingWindFraction;
2429// if (effectMag < 0f) effectMag = 0f;
2430 //if (effectMag < 0.25f) effectMag = 0.25f;
2431 //effectMag = 0.5f;
2432
2433 String modId = "slipstream_" + entity.getId();
2434 float durIn = 1f;
2435 float durOut = 3f;
2436 //durIn = 0.5f;
2437 //float sizeNormal = (15f + 30f * effectMag * effectMag) * (intensity);
2438 float sizeNormal = 5f + 10f * intensity;
2439 for (FleetMemberViewAPI view : fleet.getViews()) {
2440 view.getWindEffectDirX().shift(modId, windDir.x * sizeNormal, durIn, durOut, 1f);
2441 view.getWindEffectDirY().shift(modId, windDir.y * sizeNormal, durIn, durOut, 1f);
2442 view.getWindEffectColor().shift(modId, glowColor, durIn, durOut, 1f);
2443 }
2444 }
2445 }
2446 }
2447 }
2448
2449
2450 public void applyEffectToGhost(SectorEntityToken other, float days) {
2451// /if (true) return;
2452 //if (!(other.getCustomPlugin() instanceof SensorGhost)) return;
2453
2455 if (ghost == null) return;
2456
2457 if (other.hasTag(Tags.UNAFFECTED_BY_SLIPSTREAM)) return;
2458
2459 //SensorGhost ghost = (SensorGhost) other.getCustomPlugin();
2460 if (!containsPoint(other.getLocation(), 0f)) {
2461 return;
2462 }
2463
2464 float [] offset = getLengthAndWidthFractionWithinStream(other.getLocation());
2465 if (offset == null) {
2466 return;
2467 }
2468
2469 float distAlong = offset[0];
2470 float yOff = offset[1];
2471
2472 float intensity = getIntensity(yOff);
2473 float wMult = getWidthBasedSpeedMult(distAlong);
2474 intensity *= wMult;
2475 intensity *= getFaderBrightness(distAlong);
2476
2477 if (intensity <= 0) {
2478 return;
2479 }
2480
2481 float maxFleetBurn = ghost.getMaxBurn();
2482 float currFleetBurn = ghost.getCurrBurn();
2483
2484 float maxWindBurn = params.burnLevel * 2f;
2485
2486 float currWindBurn = intensity * maxWindBurn;
2487 float maxFleetBurnIntoWind = maxFleetBurn - Math.abs(currWindBurn);
2488 float seconds = days * Global.getSector().getClock().getSecondsPerDay();
2489
2490 Vector2f p1 = getPointAt(distAlong, yOff);
2491 Vector2f p2 = getPointAt(distAlong + 1f, yOff);
2492 if (p1 == null || p2 == null) {
2493 return;
2494 }
2495
2496 Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p1, p2));
2497 if (currWindBurn < 0) {
2498 windDir.negate();
2499 }
2500 Vector2f velDir = Misc.normalise(new Vector2f(other.getVelocity()));
2501 float baseFleetAccel = ghost.getAcceleration();
2502 if (baseFleetAccel < 10f) baseFleetAccel = 10f;
2503
2504 velDir.scale(currFleetBurn);
2505
2506 float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir);
2507
2508
2509 float windSpeed = Misc.getSpeedForBurnLevel(currWindBurn);
2510 Vector2f windVector = new Vector2f(windDir);
2511 windVector.scale(windSpeed);
2512
2513 Vector2f vel = other.getVelocity();
2514 Vector2f diff = Vector2f.sub(windVector, vel, new Vector2f());
2515 float max = diff.length();
2516 diff = Misc.normalise(diff);
2517 diff.scale(ghost.getAcceleration() * 3f * seconds);
2518 if (diff.length() > max) {
2519 diff.scale(max / diff.length());
2520 }
2521 float accelMult = 0.5f + 2f * intensity;
2522 if (fleetBurnAgainstWind > maxFleetBurnIntoWind) {
2523 accelMult += 0.25f * (fleetBurnAgainstWind - maxFleetBurnIntoWind);
2524 }
2525 windDir.scale(seconds * baseFleetAccel * accelMult);
2526
2527 ghost.getMovement().getVelocity().set(vel.x + windDir.x, vel.y + windDir.y);
2528 }
2529
2530
2531 public void applyEffectToWreck(SectorEntityToken other, float days) {
2532 if (other.hasTag(Tags.UNAFFECTED_BY_SLIPSTREAM)) return;
2533
2534 if (!containsPoint(other.getLocation(), 0f)) {
2535 return;
2536 }
2537
2538 float [] offset = getLengthAndWidthFractionWithinStream(other.getLocation());
2539 if (offset == null) {
2540 return;
2541 }
2542
2543 float distAlong = offset[0];
2544 float yOff = offset[1];
2545
2546 float intensity = getIntensity(yOff);
2547 float wMult = getWidthBasedSpeedMult(distAlong);
2548 intensity *= wMult;
2549 intensity *= getFaderBrightness(distAlong);
2550
2551 if (intensity <= 0) {
2552 return;
2553 }
2554
2555 float maxWindBurn = params.burnLevel * 0.5f;
2556 float currWindBurn = intensity * maxWindBurn;
2557
2558 Vector2f p1 = getPointAt(distAlong, yOff);
2559 Vector2f p2 = getPointAt(distAlong + 1f, yOff);
2560 if (p1 == null || p2 == null) {
2561 return;
2562 }
2563
2564 Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p1, p2));
2565 if (currWindBurn < 0) {
2566 windDir.negate();
2567 }
2568
2569 float windSpeed = Misc.getSpeedForBurnLevel(currWindBurn);
2570 Vector2f windVector = new Vector2f(windDir);
2571 windVector.scale(windSpeed);
2572 Vector2f vel = other.getVelocity();
2573 float f = 0.95f;
2574 other.getVelocity().set(vel.x * f + windVector.x * (1 - f), vel.y * f + windVector.y * (1 - f));
2575 }
2576
2577
2578 public Vector2f getPointAt(float lengthAlongStream, float offset) {
2580
2581 SlipstreamSegment curr = getSegmentForDist(lengthAlongStream);
2582 if (curr == null) return null;
2583 int index = curr.index;
2584
2585 SlipstreamSegment next = null;
2586 SlipstreamSegment next2 = null;
2587
2588 if (index >= segments.size() - 1) return null;
2589
2590 if (index % 2 == 0) {
2591 next = segments.get(index + 1);
2592 if (index >= segments.size() - 2) {
2593 next2 = new SlipstreamSegment();
2594 //next2.width = next.width;
2595 next2.wobbledWidth = next.wobbledWidth;
2596
2597 next2.normal = next.normal;
2598 //next2.dir = next.dir;
2599 next2.loc = new Vector2f(next.dir);
2600 next2.loc.scale(next.lengthToPrev);
2601 Vector2f.add(next2.loc, next.loc, next2.loc);
2602 //next2.locB = next2.loc;
2603 next2.lengthToPrev = next.lengthToPrev;
2604 } else {
2605 next2 = segments.get(index + 2);
2606 }
2607 }
2608 if (index % 2 != 0) {
2609 if (index >= segments.size() - 1) return null;
2610 curr = segments.get(index - 1);
2611 next = segments.get(index);
2612 next2 = segments.get(index + 1);
2613 }
2614
2615 float lenForT = lengthAlongStream - curr.totalLength;
2616 //float t = lenForT / (curr.lengthToNext + next.lengthToNext);
2617 float t = lenForT / (curr.lengthToNext + next2.lengthToPrev);
2618// if (t < 0) {
2619// System.out.println("wefwefe");
2620// }
2621
2622 Vector2f p0 = new Vector2f(curr.loc);
2623 Vector2f p1 = new Vector2f(next.locB);
2624 Vector2f p2 = new Vector2f(next2.loc);
2625
2626// offset *= 0.7f;
2627// p0.x += curr.normal.x * curr.width * 0.5f * offset;
2628// p0.y += curr.normal.y * curr.width * 0.5f * offset;
2629//
2630// p2.x += next2.normal.x * next2.width * 0.5f * offset;
2631// p2.y += next2.normal.y * next2.width * 0.5f * offset;
2632//
2633// p1.x += next.normal.x * next.width * 0.5f * offset;
2634// p1.y += next.normal.y * next.width * 0.5f * offset;
2635
2636 p0.x += curr.normal.x * curr.wobbledWidth * 0.5f * offset;
2637 p0.y += curr.normal.y * curr.wobbledWidth * 0.5f * offset;
2638
2639 p2.x += next2.normal.x * next2.wobbledWidth * 0.5f * offset;
2640 p2.y += next2.normal.y * next2.wobbledWidth * 0.5f * offset;
2641
2642 p1.x += next.normal.x * next.wobbledWidth * 0.5f * offset;
2643 p1.y += next.normal.y * next.wobbledWidth * 0.5f * offset;
2644
2645 //System.out.println("T: " + t);
2646 Vector2f p = Misc.bezier(p0, p1, p2, t);
2647
2648 return p;
2649 }
2650
2651 public Vector2f getNoWobblePointAt(float lengthAlongStream, float offset) {
2652 SlipstreamSegment curr = getSegmentForDist(lengthAlongStream);
2653 if (curr == null) return null;
2654 int index = curr.index;
2655 if (index >= segments.size() - 2) return null;
2656
2657 SlipstreamSegment next = segments.get(index + 1);
2658 SlipstreamSegment next2 = segments.get(index + 2);
2659
2660 if (index % 2 != 0) {
2661 curr = segments.get(index - 1);
2662 next = segments.get(index);
2663 next2 = segments.get(index + 1);
2664 }
2665
2666 float lenForT = lengthAlongStream - curr.totalLength;
2667 float t = lenForT / (curr.lengthToNext + next.lengthToNext);
2668// if (t < 0) {
2669// System.out.println("wefwefe");
2670// }
2671
2672 Vector2f p0 = new Vector2f(curr.loc);
2673 Vector2f p1 = new Vector2f(next.locB);
2674 Vector2f p2 = new Vector2f(next2.loc);
2675
2676 float edges = params.edgeWidth * 2f * 0.5f;
2677 p0.x += curr.normal.x * (curr.width - edges) * 0.5f * offset;
2678 p0.y += curr.normal.y * (curr.width - edges) * 0.5f * offset;
2679
2680 p2.x += next2.normal.x * (next2.width - edges) * 0.5f * offset;
2681 p2.y += next2.normal.y * (next2.width - edges) * 0.5f * offset;
2682
2683 p1.x += next.normal.x * (next.width - edges) * 0.5f * offset;
2684 p1.y += next.normal.y * (next.width - edges) * 0.5f * offset;
2685
2686 Vector2f p = Misc.bezier(p0, p1, p2, t);
2687
2688 return p;
2689 }
2690
2691
2692 public Vector2f getNormalAt(float lengthAlongStream) {
2693 SlipstreamSegment curr = getSegmentForDist(lengthAlongStream);
2694 if (curr == null) return null;
2695 int index = curr.index;
2696 if (index >= segments.size() - 2) return null;
2697
2698 SlipstreamSegment next = segments.get(index + 1);
2699 SlipstreamSegment next2 = segments.get(index + 2);
2700
2701 if (index % 2 != 0) {
2702 curr = segments.get(index - 1);
2703 next = segments.get(index);
2704 next2 = segments.get(index + 1);
2705 }
2706
2707 float lenForT = lengthAlongStream - curr.totalLength;
2708
2709 float f = lenForT / curr.lengthToNext;
2710 Vector2f perp;
2711 if (f < 1f) {
2712 perp = Misc.interpolateVector(curr.normal, next.normal, f);
2713 } else {
2714 f = (lenForT - curr.lengthToNext) / next.lengthToNext;
2715 perp = Misc.interpolateVector(next.normal, next2.normal, f);
2716 }
2717 return perp;
2718 }
2719
2720 public List<SlipstreamSegment> getSegmentsNear(Vector2f loc, float range) {
2721 //List<SlipstreamSegment> potential = new ArrayList<SlipstreamEntityPlugin2.SlipstreamSegment>();
2722 List<SlipstreamSegment> result = new ArrayList<SlipstreamTerrainPlugin2.SlipstreamSegment>();
2723 int boxIndex = 0;
2724 for (BoundingBox box : bounds) {
2725 if (box.pointNeedsDetailedCheck(loc, range)) {
2726 int min = boxIndex * segmentsPerBox;
2727 for (int i = min; i < min + segmentsPerBox && i < segments.size(); i++) {
2728 SlipstreamSegment curr = segments.get(i);
2729 float distSq = Misc.getDistanceSq(curr.loc, loc);
2730 float r = range + curr.width + Math.max(curr.lengthToPrev, curr.lengthToNext);
2731 if (distSq < r * r) {
2732 result.add(curr);
2733 }
2734 }
2735 }
2736 boxIndex++;
2737 }
2738 return result;
2739 }
2740
2741 @Override
2743 return false; // handled directly in advance(); also does sensor ghosts etc
2744 }
2745
2746 public boolean hasAIFlag(Object flag) {
2747 return flag == TerrainAIFlags.BREAK_OTHER_ORBITS ||
2749 }
2750
2751 @Override
2752 public boolean containsEntity(SectorEntityToken other) {
2753 //if (true) return false;
2754 if (other.getContainingLocation() != this.entity.getContainingLocation()) return false;
2755 return other != null && containsPoint(other.getLocation(), 0f) && !isPreventedFromAffecting(other);
2756 }
2757
2758 /*
2759 * The way this check works - using getLengthAndWidthFractionWithinStream() - means it can't
2760 * work with a radius > 0 - or, rather, the passed in radius value is ignored.
2761 * Update: can sort of fake it by pretending segments have extra width. Will not catch cases where something is
2762 * at the end/start of a stream, though, and might miss cases where the "wider" segments overlap
2763 * (non-Javadoc)
2764 * @see com.fs.starfarer.api.impl.campaign.terrain.BaseTerrain#containsPoint(org.lwjgl.util.vector.Vector2f, float)
2765 */
2766 @Override
2767 public boolean containsPoint(Vector2f point, float radius) {
2768 //if (true) return false;
2769 boolean doDetailedCheck = false;
2770 for (BoundingBox box : bounds) {
2771 doDetailedCheck |= box.pointNeedsDetailedCheck(point, radius);
2772 }
2773 if (!doDetailedCheck) return false;
2774
2775 float [] coords = getLengthAndWidthFractionWithinStream(point, 0f, false, radius);
2776 if (coords == null) return false;
2777
2778 float b = getFaderBrightness(coords[0]);
2779
2780 return b > 0;
2781 }
2782
2783 public List<BoundingBox> getBounds() {
2784 return bounds;
2785 }
2786
2787 transient private EnumSet<CampaignEngineLayers> layers = EnumSet.of(CampaignEngineLayers.TERRAIN_7);
2788 public EnumSet<CampaignEngineLayers> getActiveLayers() {
2789 return layers;
2790 }
2791
2792 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
2793 float opad = 10f;
2794
2795 tooltip.addTitle(getNameForTooltip());
2796 tooltip.addPara(Global.getSettings().getDescription(getTerrainId(), Type.TERRAIN).getText1(), opad);
2797
2798 tooltip.addPara("Most slipstreams are temporary, and in recent memory their ebb and flow has been "
2799 + "unusually synchronized with the standard Domain cycle.", opad);
2800
2801 tooltip.addPara("Fleets traveling inside a slipstream use %s less fuel for the distance covered.",
2802 opad, Misc.getHighlightColor(),
2803 "" + (int)Math.round((1f - FUEL_USE_MULT) * 100f) + "%");
2804
2805 tooltip.addPara("In addition, traveling at burn levels above %s is even more fuel-efficient. "
2806 + "For example, a fleet traveling at burn %s will consume half as much fuel "
2807 + "for the distance it covers.",
2808 opad,
2809 Misc.getHighlightColor(), "20", "40", "half");
2810
2811 tooltip.addPara("These fuel use reductions are not reflected by the fuel range indicator on the map.", opad);
2812
2813// tooltip.addPara("Fleets traveling at burn levels above %s become even more fuel-efficient. "
2814// + "For example, a fleet traveling at burn %s will consume %s less fuel for the "
2815// + "distance it covers.",
2816// opad,
2817// Misc.getHighlightColor(), "20", "40", "50%");
2818 }
2819
2820 @Override
2821 public boolean hasTooltip() {
2822 return true;
2823 }
2824
2825 public boolean isTooltipExpandable() {
2826 return false;
2827 }
2828
2829 public float getTooltipWidth() {
2830 return super.getTooltipWidth();
2831 }
2832
2833 public String getTerrainName() {
2834 if (params.name != null) return params.name;
2835 return "Slipstream";
2836 }
2837
2838 public String getNameForTooltip() {
2839 return "Slipstream";
2840 }
2841
2842 public String getEffectCategory() {
2843 return "slipstream";
2844 }
2845
2846 @Override
2847 public void renderOnRadar(Vector2f radarCenter, float factor, float alphaMult) {
2848 GL11.glPushMatrix();
2849 GL11.glTranslatef(-radarCenter.x * factor, -radarCenter.y * factor, 0);
2850 renderOnMap(factor, alphaMult, true, radarCenter);
2851 GL11.glPopMatrix();
2852 }
2853
2854 public List<SlipstreamSegment> getSegments() {
2855 return segments;
2856 }
2857
2858
2859 @Override
2860 public void renderOnMap(float factor, float alphaMult) {
2861 renderOnMap(factor, alphaMult, false, null);
2862 }
2863
2864 public void renderOnMap(float factor, float alphaMult, boolean forRadar, Vector2f radarCenter) {
2866 //if (true) return;
2867
2868 Set<SlipstreamSegment> nearSet = new LinkedHashSet<SlipstreamSegment>();
2869 if (forRadar) {
2870 //float radius = Global.getSettings().getFloat("campaignRadarRadius") + 1000f;
2871 float radius = Global.getSettings().getFloat("campaignRadarRadius");
2872 nearSet = new LinkedHashSet<SlipstreamSegment>(getSegmentsNear(radarCenter, radius));
2873 for (SlipstreamSegment curr : nearSet) {
2874 curr.discovered = true;
2875 }
2876 if (nearSet.isEmpty()) return;
2877 }
2878
2879 List<SlipstreamSegment> list = new ArrayList<SlipstreamSegment>();
2880 int incr = Math.min(segments.size() / 10, 5);
2881 incr = 1;
2882 if (incr < 1) incr = 1;
2883 for (int i = 0; i < segments.size(); i+=incr) {
2884 SlipstreamSegment curr = segments.get(i);
2885 if (forRadar && !nearSet.contains(curr)) continue;
2886 if (!forRadar && !curr.discovered && Global.getSettings().isCampaignSensorsOn() &&
2888 //if (!forRadar && !curr.discovered && !Global.getSettings().isDevMode()) continue;
2889 //if (!forRadar && !curr.discovered) continue;
2890 list.add(curr);
2891 if (i + incr >= segments.size() && i + 1 < segments.size()) {
2892 list.add(segments.get(segments.size() - 1));
2893 }
2894 }
2895
2896 List<List<SlipstreamSegment>> subsections = new ArrayList<List<SlipstreamSegment>>();
2897 int prevIndex = -10;
2898 List<SlipstreamSegment> subsection = new ArrayList<SlipstreamSegment>();
2899 for (SlipstreamSegment seg : list) {
2900 if (prevIndex != seg.index - 1) {
2901 if (subsection != null && !subsection.isEmpty()) {
2902 subsections.add(subsection);
2903 }
2904 subsection = new ArrayList<SlipstreamSegment>();
2905 }
2906 subsection.add(seg);
2907 prevIndex = seg.index;
2908 }
2909 if (subsection != null && !subsection.isEmpty()) {
2910 subsections.add(subsection);
2911 }
2912
2913 float texOffset = 0f;
2915 float b = fader.getBrightness();
2916 b *= 0.5f;
2917 //b *= 2f;
2918 if (fader.getState() == State.IN) {
2919 texOffset = b;
2920 } else if (fader.getState() == State.OUT) {
2921 texOffset = 1f - b;
2922 }
2923 //texOffset = mapArrowProgress;
2924 //texOffset = -texOffset;
2925 //texOffset *= 0.5f;
2926 //texOffset = 0f;
2927
2928 GL11.glPushMatrix();
2929 GL11.glScalef(factor, factor, 1f);
2930 //renderSegments(sprite, null, null, edge, alphaMult, list, texOffset % 1, true);
2931 for (List<SlipstreamSegment> subsection2 : subsections) {
2932 renderSegmentsForMap(subsection2, factor, alphaMult, forRadar, texOffset % 1);
2933 }
2934
2935 // debug: rendering encounter points
2936// if (true) {
2937// GL11.glDisable(GL11.GL_TEXTURE_2D);
2938// GL11.glEnable(GL11.GL_BLEND);
2939// GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
2940//
2941// GL11.glPointSize(20f);
2942// GL11.glEnable(GL11.GL_POINT_SMOOTH);
2943// GL11.glBegin(GL11.GL_POINTS);
2944// Misc.setColor(Color.yellow);
2945// for (Vector2f p : getEncounterPoints()) {
2946// GL11.glVertex2f(p.x, p.y);
2947// }
2948// GL11.glEnd();
2949// }
2950
2951 GL11.glPopMatrix();
2952 }
2953
2954 protected void renderSegmentsForMap(List<SlipstreamSegment> segments, float factor, float alphaMult, boolean forRadar, float phase) {
2955 //if (true) return;
2956 if (segments.isEmpty()) return;
2957
2958 //System.out.println(factor);
2959 float widthMult = 1f;
2960 float lengthPerArrowMult = 1f;
2961 float minFactor = 0.012f;
2962 if (factor < minFactor) {
2963 widthMult = minFactor / factor;
2964 lengthPerArrowMult = 2f;
2965 }
2966
2967 float lengthPerArrow = 700f;
2968 //lengthPerArrow *= sizeMult;
2969 lengthPerArrow *= lengthPerArrowMult;
2970 float start = segments.get(0).totalLength;
2971 float end = segments.get(segments.size() - 1).totalLength;
2972
2973 start = (float) (Math.floor(start / lengthPerArrow) * lengthPerArrow);
2974 end = (float) (Math.ceil(end/ lengthPerArrow) * lengthPerArrow);
2975 if (end - start < lengthPerArrow) return;
2976
2977 //Color color = Misc.setAlpha(params.maxColor, 255);
2978 Color color = params.mapColor;
2979 Color orig = color;
2980
2981 GL11.glDisable(GL11.GL_TEXTURE_2D);
2982 GL11.glEnable(GL11.GL_BLEND);
2983 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
2984 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
2985
2986 GL11.glEnable(GL11.GL_POLYGON_SMOOTH);
2987 GL11.glHint(GL11.GL_POLYGON_SMOOTH_HINT, GL11.GL_NICEST);
2988
2989 float fadeDist = 500f;
2990 //phase = 0f;
2991 GL11.glBegin(GL11.GL_TRIANGLES);
2992 for (float len = start; len < end; len += lengthPerArrow) {
2993 Vector2f p0 = getPointAt(len + phase * lengthPerArrow, 0f);
2994 Vector2f p1 = getPointAt(len + phase * lengthPerArrow + 10f, 0f);
2995 if (p0 == null || p1 == null) continue;
2996
2997 float w = getWidth(len + phase * lengthPerArrow) * widthMult;
2998 float triLength = lengthPerArrow * 0.33f;
2999 triLength = lengthPerArrow * 1f;
3000 triLength = Math.min(lengthPerArrow, (w + lengthPerArrow) / 2f);
3001
3002
3003 float a = getFaderBrightness(len + phase * lengthPerArrow + triLength/2f);
3004 if (len + phase * lengthPerArrow - start < fadeDist) {
3005 a *= (len + phase * lengthPerArrow - start) / fadeDist;
3006 }
3007 if (len + phase * lengthPerArrow > end - fadeDist) {
3008 a *= (end - (len + phase * lengthPerArrow)) / fadeDist;
3009 }
3010 if (a <= 0f) continue;
3011
3012// Vector2f t0 = new Vector2f(p0);
3013// t0.x += dir.x * triLength/2f;
3014// t0.y += dir.y * triLength/2f;
3015 Vector2f t0 = getPointAt(len + phase * lengthPerArrow + triLength/2f, 0f);
3016 if (t0 == null) continue;
3017
3018 Vector2f dir = Misc.getUnitVector(p0, t0);
3019 Vector2f perp = new Vector2f(-dir.y, dir.x);
3020
3021 Vector2f t1 = new Vector2f(p0);
3022 Vector2f t2 = new Vector2f(p0);
3023 Vector2f t3 = new Vector2f(p0);
3024 float backOffset = 0f;
3025 //offset = triLength * -0.1f;
3026 backOffset = triLength * 0.1f;
3027 t3.x -= dir.x * backOffset;
3028 t3.y -= dir.y * backOffset;
3029
3030 t1.x += perp.x * w/2f;
3031 t1.y += perp.y * w/2f;
3032 t1.x -= dir.x * triLength/2f;
3033 t1.y -= dir.y * triLength/2f;
3034
3035 t2.x -= perp.x * w/2f;
3036 t2.y -= perp.y * w/2f;
3037 t2.x -= dir.x * triLength/2f;
3038 t2.y -= dir.y * triLength/2f;
3039
3040// float f = (len - start) / (end - start);
3041// f = 1f - f;
3042// f *= 4f;
3043// f += phase * 1f;
3044// f = ((float) Math.sin(f * Math.PI * 2f) + 1f) * 0.5f;
3045// color = Misc.interpolateColor(orig, Color.white, f * 0.67f);
3046
3047
3048
3049 Misc.setColor(color, alphaMult * 1f * a);
3050 GL11.glVertex2f(t0.x, t0.y);
3051 Misc.setColor(color, alphaMult * 0f * a);
3052 GL11.glVertex2f(t1.x, t1.y);
3053 GL11.glVertex2f(t3.x, t3.y);
3054
3055 Misc.setColor(color, alphaMult * 1f * a);
3056 GL11.glVertex2f(t0.x, t0.y);
3057 Misc.setColor(color, alphaMult * 0f * a);
3058 GL11.glVertex2f(t2.x, t2.y);
3059 GL11.glVertex2f(t3.x, t3.y);
3060
3061 //float a2 = alphaMult * 0.5f;
3062// float a2 = (float) (Math.pow(alphaMult, 0.33f) * 0.5f);
3063// for (float off = -1f; off <= 1f; off += 1f) {
3064// float off2 = off / factor;
3065// off2 *= 0.5f;
3066// Misc.setColor(color, a2 * 1f * a);
3067// GL11.glVertex2f(t0.x + off2, t0.y + off2);
3068// Misc.setColor(color, a2 * 0f * a);
3069// GL11.glVertex2f(t1.x + off2, t1.y + off2);
3070// GL11.glVertex2f(t3.x + off2, t3.y + off2);
3071//
3072// Misc.setColor(color, a2 * 1f * a);
3073// GL11.glVertex2f(t0.x + off2, t0.y + off2);
3074// Misc.setColor(color, a2 * 0f * a);
3075// GL11.glVertex2f(t2.x + off2, t2.y + off2);
3076// GL11.glVertex2f(t3.x + off2, t3.y + off2);
3077// }
3078
3079 color = orig;
3080
3081 }
3082 GL11.glEnd();
3083
3084 GL11.glEnable(GL11.GL_TEXTURE_2D);
3085 GL11.glEnable(GL11.GL_BLEND);
3086 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
3087 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
3088 SpriteAPI line = Global.getSettings().getSprite("graphics/hud/line4x4.png");
3089 line.bindTexture();
3090
3091 float incr = 100f;
3092 float lineW = 50f;
3093 GL11.glBegin(GL11.GL_QUAD_STRIP);
3094 for (float len = start; len < end; len += incr) {
3095 Vector2f p0 = getPointAt(len, 0f);
3096 Vector2f p1 = getPointAt(len + 10f, 0f);
3097 if (p0 == null || p1 == null) continue;
3098
3099 Vector2f dir = Misc.getUnitVector(p0, p1);
3100 Vector2f perp = new Vector2f(-dir.y, dir.x);
3101 float w = lineW;
3102
3103 Vector2f p2 = new Vector2f(p0);
3104 Vector2f p3 = new Vector2f(p0);
3105 p2.x += perp.x * w * 0.5f;
3106 p2.y += perp.y * w * 0.5f;
3107 p3.x -= perp.x * w * 0.5f;
3108 p3.y -= perp.y * w * 0.5f;
3109
3110 float a = getFaderBrightness(len);
3111 if (len - start < fadeDist) {
3112 a *= (len - start) / fadeDist;
3113 }
3114 if (len > end - fadeDist) {
3115 a *= (end - len) / fadeDist;
3116 }
3117
3118 Misc.setColor(color, alphaMult * a * 0.5f);
3119 GL11.glTexCoord2f(0f, 0f);
3120 GL11.glVertex2f(p2.x, p2.y);
3121 GL11.glTexCoord2f(0f, 1f);
3122 GL11.glVertex2f(p3.x, p3.y);
3123 }
3124 GL11.glEnd();
3125
3126 GL11.glDisable(GL11.GL_POLYGON_SMOOTH);
3127 }
3128
3129
3130 protected void doSoundPlayback(float amount) {
3131 //if (true) return;
3132
3134 if (fleet != null && entity.isInCurrentLocation()) {
3135 Vector2f loc = fleet.getLocation();
3136
3137 float outerPlaybackRange = (float) getSpec().getCustom().optDouble("outsideSoundRange", 1000f);
3138 float [] coords = getLengthAndWidthFractionWithinStream(loc, outerPlaybackRange + 2000f, true, 0f);
3139
3140 float innerVolume = 0f;
3141 float innerPitch = 1f;
3142 float outerVolume = 0f;
3143 float outerPitch = 1f;
3144
3145 SlipstreamSegment segment = null;
3146 List<SlipstreamSegment> near = getSegmentsNear(loc, outerPlaybackRange + 2000f);
3147 float pointProximityOuterVolume = 0f;
3148 for (SlipstreamSegment curr : near) {
3149 float dist = Misc.getDistance(loc, curr.loc);
3150 float check = curr.wobbledWidth / 2f + outerPlaybackRange;
3151 if (dist < check) {
3152 float volume = 1f - dist / check;
3153 volume *= curr.bMult * curr.fader.getBrightness();
3154 if (volume > pointProximityOuterVolume) {
3155 pointProximityOuterVolume = volume;
3156 segment = curr;
3157 }
3158 }
3159 }
3160
3161 float fMult = coords == null ? 0f : getFaderBrightness(coords[0]);
3162 if (fMult <= 0f) {
3163 outerVolume = pointProximityOuterVolume;
3164 } else {
3165 float wMult = getWidthBasedSpeedMult(coords[0]);
3166 float f = Math.abs(coords[1]);
3167
3168 if (f <= 1f) {
3169 float intensity = getIntensity(f);
3170 float minPitch = (float) getSpec().getCustom().optDouble("minPitch", 0.5f);
3171 float maxPitch = (float) getSpec().getCustom().optDouble("maxPitch", 1.25f);
3172 //innerVolume = 0f + 1f * (intensity * wMult);
3173 innerVolume = 0f + 1f * (Math.min(1f, intensity * 2f) * wMult);
3174 innerPitch = minPitch + (1f - minPitch) * intensity * wMult;
3175 if (innerPitch > maxPitch) innerPitch = maxPitch;
3176 outerVolume = 1f;
3177 if (intensity >= 0.5f) {
3178 outerVolume = 0f;
3179 }
3180 } else {
3181 float distFromStream = 0f;
3182 distFromStream = getWidth(coords[0]) * 0.5f * (f - 1f);
3183 if (distFromStream < outerPlaybackRange) {
3184 float intensity = 1f - distFromStream / outerPlaybackRange;
3185 outerVolume = 0f + 1f * (intensity * wMult);
3186 }
3187 }
3188
3189 innerVolume *= fMult;
3190 outerVolume *= fMult;
3191 outerVolume = Math.max(outerVolume, pointProximityOuterVolume);
3192 }
3193 outerVolume = Math.min(outerVolume, 1f - innerVolume);
3194 //outerVolume = Math.min(outerVolume, 1f - Math.max(0f, innerVolume - 0.25f) * (1f / .75f));
3195
3196 if (innerVolume < 0) innerVolume = 0;
3197 if (innerVolume > 1) innerVolume = 1;
3198 if (outerVolume > 1) outerVolume = 1;
3199 if (outerVolume < 0) outerVolume = 0;
3200
3201// if (innerVolume > 0) {
3202// outerVolume = 0;
3203// innerVolume = 1;
3204// }
3205// if (innerVolume != 0 || outerVolume != 0) {
3206// System.out.println("inner: " + innerVolume + ", outer: " + outerVolume);
3207// }
3208
3209 float loopFade = 0.5f;
3210 //loopFade = 5f;
3211 String soundId = getSpec().getLoopOne();
3212
3213 float filterMult = innerVolume;
3214 if (innerVolume > 0f) {
3215 filterMult = 1f;
3216// } else if (outerVolume > 0f) {
3217// filterMult = Math.min(1f, outerVolume * 2f);
3218// if (filterMult < 0.5f) filterMult *= filterMult;
3219// }
3220 } else if (outerVolume > 0.5f) {
3221 filterMult = Math.min(1f, (outerVolume - 0.5f) * 4f);
3222 }
3223 //System.out.println("Filter: " + filterMult);
3224 if (innerVolume > 0) {
3225 float gain = (float) getSpec().getCustom().optDouble("gain", 0.75f);
3226 float gainHF = (float) getSpec().getCustom().optDouble("gainHF", 0.5f);
3227
3229 Math.max(0f, 1f - (1f - gain) * innerVolume),
3230 Math.max(0f, 1f - Math.min(1f - gainHF, innerVolume)));
3231// Math.max(0f, 1f - 0.25f * innerVolume),
3232// Math.max(0f, 1f - Math.min(0.5f, innerVolume)));
3233 }
3234
3235 if (soundId != null && innerVolume > 0f) {
3236 Global.getSoundPlayer().playLoop(soundId, fleet, innerPitch,
3237 getLoopOneVolume() * innerVolume, fleet.getLocation(), Misc.ZERO, loopFade, loopFade);
3238 }
3239 soundId = getSpec().getLoopTwo();
3240 if (soundId != null && outerVolume > 0f) {
3241 Vector2f playbackLoc = fleet.getLocation();
3242 if (segment != null) playbackLoc = segment.loc;
3243 Global.getSoundPlayer().playLoop(soundId, fleet, outerPitch,
3244 getLoopTwoVolume() * outerVolume, playbackLoc, Misc.ZERO, loopFade, loopFade);
3245 }
3246
3247 float suppressionMult = innerVolume;
3248 suppressionMult = filterMult;
3249 Global.getSector().getCampaignUI().suppressMusic(getSpec().getMusicSuppression() * suppressionMult);
3250 }
3251 }
3252
3253
3254 @Override
3255 protected boolean shouldPlayLoopOne() {
3256 return false;
3257 }
3258
3259 @Override
3260 protected boolean shouldPlayLoopTwo() {
3261 return false;
3262 }
3263
3264 public List<Vector2f> getEncounterPoints() {
3265 if (encounterPoints == null) {
3266 encounterPoints = new ArrayList<Vector2f>();
3268 }
3269 return encounterPoints;
3270 }
3271
3273 encounterPoints = new ArrayList<Vector2f>();
3274
3275 List<List<SlipstreamSegment>> sections = new ArrayList<List<SlipstreamSegment>>();
3276
3277 boolean currSectionIsBreak = false;
3278 List<SlipstreamSegment> list = new ArrayList<SlipstreamSegment>();
3279 for (int i = 0; i < segments.size(); i++) {
3280 SlipstreamSegment curr = segments.get(i);
3281 boolean currSegmentIsBreak = curr.bMult <= 0f;
3282 if (list.isEmpty()) {
3283 currSectionIsBreak = currSegmentIsBreak;
3284 }
3285 if (currSectionIsBreak == currSegmentIsBreak) {
3286 list.add(curr);
3287 } else {
3288 if (!list.isEmpty()) {
3289 sections.add(list);
3290 }
3291 list = new ArrayList<SlipstreamSegment>();
3292 i--;
3293 }
3294 }
3295
3296 boolean prevSectionWasLongEnough = false;
3297 for (List<SlipstreamSegment> section : sections) {
3298 boolean sectionIsBreak = section.get(0).bMult <= 0;
3299 float sectionLength = section.get(section.size() - 1).totalLength - section.get(0).totalLength;
3300 //if (sectionIsBreak && prevSectionWasLongEnough && section.size() > 5f) {
3301 if (sectionIsBreak && prevSectionWasLongEnough && sectionLength >= 1000f) {// && sectionLength < 4000f) {
3302 Vector2f loc = new Vector2f(section.get(0).loc);
3303 Vector2f dir = new Vector2f(section.get(0).dir);
3304 dir.scale(Math.min(1000f, sectionLength * 0.4f));
3305 Vector2f.add(dir, loc, loc);
3306 encounterPoints.add(loc);
3307 }
3308
3309 if (!sectionIsBreak && section.size() >= 10f) {
3310 prevSectionWasLongEnough = true;
3311 } else {
3312 prevSectionWasLongEnough = false;
3313 }
3314 }
3315 if (prevSectionWasLongEnough) {
3316 List<SlipstreamSegment> section = sections.get(sections.size() - 1);
3317 Vector2f loc = new Vector2f(section.get(section.size() - 1).loc);
3318 Vector2f dir = new Vector2f(section.get(section.size() - 1).dir);
3319 dir.scale(1000f);
3320 Vector2f.add(dir, loc, loc);
3321 encounterPoints.add(loc);
3322 }
3323 }
3324
3325
3326}
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
static SettingsAPI getSettings()
Definition Global.java:57
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:49
static SectorAPI getSector()
Definition Global.java:65
static SensorGhost getGhostFor(SectorEntityToken entity)
static final String FUEL_USE_NOT_SHOWN_ON_MAP_MULT
Definition Stats.java:63
static final String SLIPSTREAM_VISIBLE_IN_ABYSS
Definition Tags.java:482
static final String UNAFFECTED_BY_SLIPSTREAM
Definition Tags.java:463
static final String FADING_OUT_AND_EXPIRING
Definition Tags.java:341
void preventOtherTerrainFromAffecting(SectorEntityToken other)
boolean isPreventedFromAffecting(SectorEntityToken other)
void setTileState(Vector2f loc, float radius, CellState state, float waitDur, float signalDur)
static BoundingBox create(List< SlipstreamSegment > segments)
static void genNoise1D(Random random, float[] noise, int size, float spikes)
static float[] initNoise1D(Random random, int size, float spikes)
void renderOnMap(float factor, float alphaMult, boolean forRadar, Vector2f radarCenter)
void renderOnRadar(Vector2f radarCenter, float factor, float alphaMult)
void despawn(float despawnDelay, float despawnDays, Random random)
void renderSegmentsForMap(List< SlipstreamSegment > segments, float factor, float alphaMult, boolean forRadar, float phase)
void init(String terrainId, SectorEntityToken entity, Object pluginParams)
float[] getLengthAndWidthFractionWithinStream(Vector2f loc, float extraRangeForCheck, boolean allowOutsideStream, float extraWidthForSegments)
List< SlipstreamSegment > getSegmentsNear(Vector2f loc, float range)
void renderSegments(SpriteAPI sprite0, SpriteAPI sprite1, SpriteAPI sprite2, SpriteAPI edge, float alpha, List< SlipstreamSegment > segments, float extraTX, boolean forMap)
static float getDistanceSq(Vector2f v1, Vector2f v2)
Definition Misc.java:613
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
Definition Misc.java:1196
static Vector2f bezier(Vector2f p0, Vector2f p1, Vector2f p2, float t)
Definition Misc.java:6383
static void setColor(Color color)
Definition Misc.java:4006
static Color setAlpha(Color color, int alpha)
Definition Misc.java:1316
static Vector2f rotateAroundOrigin(Vector2f v, float angle)
Definition Misc.java:1205
static final Vector2f ZERO
Definition Misc.java:249
static void fadeAndExpire(SectorEntityToken entity)
Definition Misc.java:3133
static Vector2f intersectLines(Vector2f a1, Vector2f a2, Vector2f b1, Vector2f b2)
Definition Misc.java:1994
static float getAngleDiff(float from, float to)
Definition Misc.java:1716
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
static boolean isReversePolarity(SectorEntityToken entity)
Definition Misc.java:6718
static Vector2f getUnitVector(Vector2f from, Vector2f to)
Definition Misc.java:1191
static float getClosestTurnDirection(float facing, float desired)
Definition Misc.java:2102
static float getDistanceToPlayerLY(Vector2f locInHyper)
Definition Misc.java:626
static CampaignTerrainAPI getHyperspaceTerrain()
Definition Misc.java:2308
static Color getHighlightColor()
Definition Misc.java:792
static float interpolate(float from, float to, float progress)
Definition Misc.java:1291
static Vector2f interpolateVector(Vector2f from, Vector2f to, float progress)
Definition Misc.java:1282
static float getAbyssalDepth(Vector2f loc)
Definition Misc.java:2330
static Color interpolateColor(Color from, Color to, float progress)
Definition Misc.java:1261
static float getSpeedForBurnLevel(float burnLevel)
Definition Misc.java:1671
static float getAngleInDegrees(Vector2f v)
Definition Misc.java:1126
static Vector2f normalise(Vector2f v)
Definition Misc.java:1134
Description getDescription(String id, Type type)
boolean getBoolean(String key)
SpriteAPI getSprite(String filename)
void applyLowPassFilter(float gain, float gainHF)
void playLoop(String id, Object playingEntity, float pitch, float volume, Vector2f loc, Vector2f vel)
List< FleetMemberViewAPI > getViews()
List< CustomCampaignEntityAPI > getCustomEntities()
List< CampaignFleetAPI > getFleets()
void addFloatingText(String text, Color color, float duration)
void set(String key, Object value)
boolean isNearViewport(Vector2f loc, float nearDistance)
void addTemporaryModMult(float durInDays, String source, String desc, float value, StatBonus stat)
LabelAPI addPara(String format, float pad, Color hl, String... highlights)