001package com.fs.starfarer.api.impl.campaign.velfield; 002 003import java.util.ArrayList; 004import java.util.EnumSet; 005import java.util.Iterator; 006import java.util.LinkedHashMap; 007import java.util.LinkedHashSet; 008import java.util.List; 009import java.util.Map; 010import java.util.Random; 011import java.util.Set; 012 013import java.awt.Color; 014 015import org.lwjgl.input.Mouse; 016import org.lwjgl.opengl.GL11; 017import org.lwjgl.opengl.GL14; 018import org.lwjgl.util.vector.Vector2f; 019 020import com.fs.starfarer.api.Global; 021import com.fs.starfarer.api.campaign.CampaignEngineLayers; 022import com.fs.starfarer.api.campaign.CampaignFleetAPI; 023import com.fs.starfarer.api.campaign.SectorEntityToken; 024import com.fs.starfarer.api.campaign.TerrainAIFlags; 025import com.fs.starfarer.api.combat.ViewportAPI; 026import com.fs.starfarer.api.fleet.FleetMemberViewAPI; 027import com.fs.starfarer.api.graphics.SpriteAPI; 028import com.fs.starfarer.api.impl.campaign.DebugFlags; 029import com.fs.starfarer.api.impl.campaign.abilities.ReversePolarityToggle; 030import com.fs.starfarer.api.impl.campaign.abilities.SustainedBurnAbility; 031import com.fs.starfarer.api.impl.campaign.ghosts.SensorGhost; 032import com.fs.starfarer.api.impl.campaign.ghosts.SensorGhostManager; 033import com.fs.starfarer.api.impl.campaign.ids.Entities; 034import com.fs.starfarer.api.impl.campaign.ids.Stats; 035import com.fs.starfarer.api.impl.campaign.ids.Tags; 036import com.fs.starfarer.api.impl.campaign.terrain.BaseTerrain; 037import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin; 038import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin.CellState; 039import com.fs.starfarer.api.loading.Description.Type; 040import com.fs.starfarer.api.ui.TooltipMakerAPI; 041import com.fs.starfarer.api.util.FaderUtil; 042import com.fs.starfarer.api.util.FaderUtil.State; 043import com.fs.starfarer.api.util.Misc; 044import com.fs.starfarer.api.util.MutatingVertexUtil; 045import com.fs.starfarer.api.util.WeightedRandomPicker; 046 047public class SlipstreamTerrainPlugin2 extends BaseTerrain { 048 049 public static float FUEL_USE_MULT = 0.5f; 050 public static String FUEL_USE_MODIFIER_DESC = "Inside slipstream"; 051 052 public static class SlipstreamParams2 { 053 public String enteringSlipstreamTextOverride = null; 054 public Float enteringSlipstreamTextDurationOverride = null; 055 public boolean forceNoWindVisualEffectOnFleets = false; 056 public String spriteKey1 = "slipstream0"; 057 public String spriteKey2 = "slipstream1"; 058 public String spriteKey3 = "slipstream2"; 059 public String edgeKey = "slipstream_edge"; 060 public Color spriteColor = Color.white; 061 public Color windGlowColor = new Color(0.65f, 0.5f, 1f, 0.75f); 062 public Color edgeColor = Color.white; 063 public float baseWidth = 768f; 064 public float widthForMaxSpeed = 768f; 065 public float edgeWidth = 256f; 066 public float areaPerParticle = 10000; 067 public int maxParticles = 2000; 068 public float minSpeed; 069 public float maxSpeed; 070 public Color minColor = new Color(0.5f, 0.3f, 0.75f, 0.1f); 071 public Color maxColor = new Color(0.5f, 0.6f, 1f, 0.3f); 072 public Color mapColor = new Color(0.5f, 0.6f, 1f, 1f); 073 //public Color maxColor = new Color(0.5f, 0.6f, 1f, 0.5f); 074 public float minDur = 2f; 075 public float maxDur = 6f; 076 public float particleFadeInTime = 1f; 077 public float lineLengthFractionOfSpeed = 0.25f; 078 079 public int burnLevel = 30; 080 public int maxBurnLevelForTextureScroll = 30; 081 public boolean slowDownInWiderSections = true; 082 public float widthForMaxSpeedMinMult = 0.67f; 083 public float widthForMaxSpeedMaxMult = 1.5f; 084 public float accelerationMult = 1f; 085 public String name = null; 086 087 public float texScrollMult0 = 0f; 088 public float texScrollMult1 = -1.13f; 089 public float texScrollMult2 = -0.28f; 090 091 Object readResolve() { 092 if (accelerationMult <= 0f) { 093 accelerationMult = 1f; 094 } 095 return this; 096 } 097 } 098 099 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 185 public SlipstreamTerrainPlugin2() { 186 } 187 188 public boolean isDespawning() { 189 return entity.hasTag(Tags.FADING_OUT_AND_EXPIRING) || despawnNoise != null; 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); 208 SlipstreamBuilder.normalizeNoise1D(spawnNoise); 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; 226 float noise = SlipstreamBuilder.getInterpNoise(spawnNoise, t); 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); 258 SlipstreamBuilder.normalizeNoise1D(despawnNoise); 259 } 260 261 protected void advanceDespawn(float amount) { 262// if (isDespawning()) { 263// System.out.println("3f23f23f32"); 264// } 265 if (despawnNoise == null) return; 266 if (entity.hasTag(Tags.FADING_OUT_AND_EXPIRING)) 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; 281 float noise = SlipstreamBuilder.getInterpNoise(despawnNoise, t); 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) { 289 Misc.fadeAndExpire(entity); 290 despawnNoise = null; 291 } 292 } 293 294 public void setNeedsRecompute() { 295 this.needsRecompute = true; 296 } 297 298 public void updateLengthToIndexMap() { 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); 360 setNeedsRecompute(); 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 } 388 if (entity.isInCurrentLocation()) { 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 406 recomputeIfNeeded(); 407 advanceNearbySegments(amount); 408 409 addParticles(); 410 advanceParticles(amount); 411 412 advanceSpawn(amount); 413 advanceDespawn(amount); 414 415 if (entity.isInCurrentLocation()) { 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 595 updateLengthToIndexMap(); 596 updateBoundingBoxes(); 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 622 CampaignFleetAPI pf = Global.getSector().getPlayerFleet(); 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 638 ViewportAPI viewport = Global.getSector().getViewport(); 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 653 HyperspaceTerrainPlugin plugin = (HyperspaceTerrainPlugin) Misc.getHyperspaceTerrain().getPlugin(); 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; 762 ViewportAPI viewport = Global.getSector().getViewport(); 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; 770 locFrom = Global.getSector().getPlayerFleet().getLocationInHyperspace(); 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; 819 WeightedRandomPicker<SlipstreamSegment> segmentPicker = new WeightedRandomPicker<SlipstreamTerrainPlugin2.SlipstreamSegment>(); 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; 1048 public SlipstreamBuilder getBuilder() { 1049 return builder; 1050 } 1051 1052 public void setBuilder(SlipstreamBuilder builder) { 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; 1062 recomputeIfNeeded(); 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(); 1089 float wmx = Global.getSector().getViewport().convertScreenXToWorldX(mx); 1090 float wmy = Global.getSector().getViewport().convertScreenYToWorldY(my); 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; 1285//// if (f > 1f) { 1286//// System.out.println("wefwefe " + index); 1287//// } 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// 1410//// GL11.glVertex2f(curr.loc.x, curr.loc.y); 1411//// GL11.glVertex2f(next.loc.x, next.loc.y); 1412//// GL11.glVertex2f(next2.loc.x, next2.loc.y); 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); 1447//// float tPrev = (prev.lengthToNext + len) / (prev.lengthToNext + curr.lengthToNext); 1448//// Vector2f pPrev = Misc.bezier(prev.loc, curr.loc, next.loc, tPrev); 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// 1487//// GL11.glVertex2f(curr.loc.x, curr.loc.y); 1488//// GL11.glVertex2f(next.loc.x, next.loc.y); 1489//// GL11.glVertex2f(next2.loc.x, next2.loc.y); 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) { 1516 float[] place = getLengthAndWidthFractionWithinStream(Global.getSector().getPlayerFleet().getLocation()); 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); 1527 p = Global.getSector().getPlayerFleet().getLocation(); 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; 1734 if (entity.hasTag(Tags.SLIPSTREAM_VISIBLE_IN_ABYSS)) return 1f; 1735 float bMult = 1f; 1736 if (!forMap) { 1737 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 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 1993 /** 1994 * result[0] = actual distance along the length of the slipstream 1995 * result[1] = offset along the width of the slipstream, 1996 * 0 = on center, 1 = on edge along normal, -1 = on edge along negative of normal 1997 * null if outside stream 1998 * Assumes rectangular, non-tapered stream 1999 * @param loc 2000 * @return 2001 */ 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) { 2006 recomputeIfNeeded(); 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); 2097 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) { 2098 if (isPreventedFromAffecting(fleet)) continue; 2099 applyEffect(fleet, days); 2100 } 2101 //for (SectorEntityToken entity : entity.getContainingLocation().getEntitiesWithTag(Tags.GHOST)) { 2102 for (SectorEntityToken entity : entity.getContainingLocation().getCustomEntities()) { 2103 if (entity.hasTag(Tags.GHOST)) { 2104 if (isPreventedFromAffecting(entity)) continue; 2105 applyEffectToGhost(entity, days); 2106 } else if (Entities.WRECK.equals(entity.getCustomEntityType())) { 2107 if (isPreventedFromAffecting(entity)) continue; 2108 applyEffectToWreck(entity, days); 2109 } 2110 2111 } 2112 } 2113 2114 //protected boolean playerWasInSlipstream = false; 2115 protected int playerWasInSlipstreamFramesAgo = 1000; 2116 protected float playerDesiredYOffset = 1000; 2117 protected void playerNoLongerinSlipstream() { 2118 playerWasInSlipstreamFramesAgo++; 2119 if (playerWasInSlipstreamFramesAgo > 1000) { 2120 playerWasInSlipstreamFramesAgo = 1000; 2121 } 2122 playerDesiredYOffset = 1000; 2123 } 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()) { 2129 playerNoLongerinSlipstream(); 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()) { 2147 playerNoLongerinSlipstream(); 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()) { 2175 playerNoLongerinSlipstream(); 2176 } 2177 return; 2178 } 2179 2180 preventOtherTerrainFromAffecting(fleet); 2181 fleet.getMemoryWithoutUpdate().set(SustainedBurnAbility.SB_NO_STOP, true, 0.1f); 2182 fleet.getMemoryWithoutUpdate().set(SustainedBurnAbility.SB_NO_SLOW, true, 0.1f); 2183 2184 if (fleet.isPlayerFleet()) { 2185 //if (!playerWasInSlipstream) { 2186 // playerWasInSlipstream = true; 2187 if (playerWasInSlipstreamFramesAgo > 5) { 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 } 2200 playerWasInSlipstreamFramesAgo = 0; 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()) { 2227 playerNoLongerinSlipstream(); 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(); 2259 float wmx = Global.getSector().getViewport().convertScreenXToWorldX(mx); 2260 float wmy = Global.getSector().getViewport().convertScreenYToWorldY(my); 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); 2279 if (playerDesiredYOffset <= 1f && playerDesiredYOffset >= -1f) { 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( 2293 Misc.getAngleInDegrees(fleet.getLocation(), fleet.getMoveDestination())); 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) { 2316 float polarityMult = fleet.getMemoryWithoutUpdate().getFloat(ReversePolarityToggle.POLARITY_SPEED_MULT); 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", 2394 FUEL_USE_MODIFIER_DESC, FUEL_USE_MULT, 2395 fleet.getStats().getDynamic().getStat(Stats.FUEL_USE_NOT_SHOWN_ON_MAP_MULT)); 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; 2404 if (fleet.getMemoryWithoutUpdate().contains(ReversePolarityToggle.POLARITY_WIND_GLOW_COLOR_KEY)) { 2405 glowColor = (Color) fleet.getMemoryWithoutUpdate().get(ReversePolarityToggle.POLARITY_WIND_GLOW_COLOR_KEY); 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) { 2421 windDir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p1, p2)); 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 2454 SensorGhost ghost = SensorGhostManager.getGhostFor(other); 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) { 2579 recomputeIfNeeded(); 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 2742 protected boolean shouldCheckFleetsToApplyEffect() { 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 || 2748 flag == TerrainAIFlags.MOVES_FLEETS; 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) { 2865 recomputeIfNeeded(); 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() && 2887 (!DebugFlags.SLIPSTREAM_DEBUG || DebugFlags.USE_SLIPSTREAM_VISIBILITY_IN_DEBUG_MODE)) continue; 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; 2914 FaderUtil fader = Global.getSector().getCampaignUI().getSharedFader(); 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 3133 CampaignFleetAPI fleet = Global.getSector().getPlayerFleet(); 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 3228 Global.getSoundPlayer().applyLowPassFilter( 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>(); 3267 recomputeEncounterPoints(); 3268 } 3269 return encounterPoints; 3270 } 3271 3272 public void recomputeEncounterPoints() { 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