001package com.fs.starfarer.api.impl.campaign.terrain; 002 003import java.awt.Color; 004import java.util.EnumSet; 005 006import org.lwjgl.opengl.GL11; 007import org.lwjgl.util.vector.Vector2f; 008 009import com.fs.starfarer.api.Global; 010import com.fs.starfarer.api.campaign.CampaignEngineLayers; 011import com.fs.starfarer.api.campaign.CampaignFleetAPI; 012import com.fs.starfarer.api.campaign.SectorEntityToken; 013import com.fs.starfarer.api.combat.ViewportAPI; 014import com.fs.starfarer.api.fleet.FleetMemberViewAPI; 015import com.fs.starfarer.api.graphics.SpriteAPI; 016import com.fs.starfarer.api.loading.Description.Type; 017import com.fs.starfarer.api.ui.Alignment; 018import com.fs.starfarer.api.ui.TooltipMakerAPI; 019import com.fs.starfarer.api.util.FaderUtil; 020import com.fs.starfarer.api.util.Misc; 021 022public class WavefrontTerrainPlugin extends BaseTerrain { 023 024 public static class WavefrontParams { 025 public float burnLevel; 026 public float crLossMult; 027 public float arcOriginRange; 028 public float startWidth; 029 public float widthExpansionRate; 030 public float startThickness; 031 public float thicknessExpansionRate; 032 public float duration; 033 public float angle; 034 public WavefrontParams(float burnLevel, float crLossMult, 035 float arcOriginRange, float startWidth, 036 float widthExpansionRate, float startThickness, 037 float thicknessExpansionRate, float duration, float angle) { 038 this.burnLevel = burnLevel; 039 this.crLossMult = crLossMult; 040 this.arcOriginRange = arcOriginRange; 041 this.startWidth = startWidth; 042 this.widthExpansionRate = widthExpansionRate; 043 this.startThickness = startThickness; 044 this.thicknessExpansionRate = thicknessExpansionRate; 045 this.duration = duration; 046 this.angle = angle; 047 } 048 049 } 050 051 transient protected SpriteAPI texture = null; 052 protected WavefrontParams params; 053 protected Vector2f arcOrigin = new Vector2f(); 054 protected Vector2f velDir = new Vector2f(), p1 = new Vector2f(), p2 = new Vector2f(); 055 protected float distanceTravelled = 0f; 056 protected float currentWidth; 057 protected float currentThickness; 058 protected float currentArc = 0f; 059 protected float phaseAngle; 060 protected int numSegments; 061 protected FaderUtil fader = new FaderUtil(0, 0.2f, 1f); 062 063 public void init(String terrainId, SectorEntityToken entity, Object param) { 064 super.init(terrainId, entity, param); 065 params = (WavefrontParams) param; 066 fader.fadeIn(); 067 068 velDir = Misc.getUnitVectorAtDegreeAngle(params.angle); 069 070 currentThickness = params.startThickness; 071 currentWidth = params.startWidth; 072 073 numSegments = (int) ((params.startWidth + params.widthExpansionRate * params.duration) / getPixelsPerSegment()); 074 if (numSegments < 5) numSegments = 5; 075 076 phaseAngle = (float) Math.random() * 360f; 077 078 readResolve(); 079 } 080 081 Object readResolve() { 082 texture = Global.getSettings().getSprite("terrain", "wavefront"); 083 layers = EnumSet.of(CampaignEngineLayers.TERRAIN_6, CampaignEngineLayers.TERRAIN_10); 084 return this; 085 } 086 087 protected float getPixelsPerSegment() { 088 return 25f; 089 } 090 091 Object writeReplace() { 092 return this; 093 } 094 095 transient private EnumSet<CampaignEngineLayers> layers = EnumSet.of(CampaignEngineLayers.TERRAIN_6, CampaignEngineLayers.TERRAIN_10); 096 public EnumSet<CampaignEngineLayers> getActiveLayers() { 097 return layers; 098 } 099 100 public WavefrontParams getParams() { 101 return params; 102 } 103 104 protected void updateArcOrigin() { 105 arcOrigin = Misc.getUnitVectorAtDegreeAngle(params.angle); 106 arcOrigin.scale(params.arcOriginRange + distanceTravelled); 107 arcOrigin.negate(); 108 Vector2f.add(entity.getLocation(), arcOrigin, arcOrigin); 109 } 110 111 public void advance(float amount) { 112 super.advance(amount); 113 114 // doing this every frame in case something manupulates the location directly 115 // such as the location being set initially 116 updateArcOrigin(); 117 updateArcOfCurrWidth(); 118 119 float days = Global.getSector().getClock().convertToDays(amount); 120 fader.advance(days); 121 params.duration -= days; 122 if (params.duration <= 0) { 123 fader.fadeOut(); 124 } 125 if (fader.isFadedOut()) { 126 entity.getContainingLocation().removeEntity(entity); 127 return; 128 } 129 130 currentWidth += params.widthExpansionRate * days; 131 currentThickness += params.thicknessExpansionRate * days; 132 133 float speed = Misc.getSpeedForBurnLevel(params.burnLevel); 134 speed *= fader.getBrightness(); 135 distanceTravelled += speed * amount; 136 137 entity.getVelocity().set(velDir); 138 entity.getVelocity().scale(speed); 139 140// arcOrigin.x += entity.getVelocity().x * amount; 141// arcOrigin.y += entity.getVelocity().y * amount; 142 143// float angle1 = Misc.getAngleInDegrees(arcOrigin, p1); 144// float angle2 = Misc.getAngleInDegrees(arcOrigin, p2); 145// float startRad = (float) Math.toRadians(angle1); 146// float endRad = (float) Math.toRadians(angle2); 147// float spanRad = Math.abs(endRad - startRad); 148// float periodMult = 3.1415f * 2f / spanRad * 0.25f * currentWidth / 800f; 149 150 phaseAngle += days * 360f * 0.2f * 1f * (1f / (currentWidth / 800f)); 151 //phaseAngle += days * 360f * 0.2f; 152 153 //phaseAngle += days * 360f * 0.2f * 1f; 154 //phaseAngle = Misc.normalizeAngle(phaseAngle); // not necessary due to wavefront lifetime, also need to normalise phaseAngleRad later before multiplying by periodMult. 155 } 156 157 public void render(CampaignEngineLayers layer, ViewportAPI viewport) { 158 //if (true) return; 159 160 float alphaMult = viewport.getAlphaMult(); 161 alphaMult *= fader.getBrightness(); 162 if (alphaMult <= 0) return; 163 164 float xOff = 0; 165 float yOff = 0; 166 //float phaseAngle = this.phaseAngle; 167 if (layer == CampaignEngineLayers.TERRAIN_10) { 168 //return; 169 float offset = 50; 170 if (offset > currentThickness * 0.5f) { 171 offset = currentThickness * 0.5f; 172 } 173 xOff = velDir.x * -offset; 174 yOff = velDir.y * -offset; 175 //phaseAngle = this.phaseAngle + 35f; 176 //return; 177 } 178 179 180 181 float bandWidthInTexture = 256f; 182 float bandIndex; 183 184 float max = params.arcOriginRange + distanceTravelled; 185 float min = max - currentThickness; 186 float radStart = min; 187 float radEnd = max; 188 189 if (radEnd < radStart + 10f) radEnd = radStart + 10f; 190 191 float segments = numSegments; 192 193 float angle1 = Misc.getAngleInDegrees(arcOrigin, p1); 194 float angle2 = Misc.getAngleInDegrees(arcOrigin, p2); 195 float turnDir = Misc.getClosestTurnDirection(Misc.getUnitVectorAtDegreeAngle(angle1), 196 Misc.getUnitVectorAtDegreeAngle(angle2)); 197 198 float startRad = (float) Math.toRadians(angle1); 199 float endRad = (float) Math.toRadians(angle2); 200 if (startRad > endRad) { 201 endRad += Math.PI * 2f; 202 } 203 float spanRad = Math.abs(endRad - startRad); 204 float anglePerSegment = spanRad / segments; 205 206 Vector2f loc = arcOrigin; 207 float x = loc.x; 208 float y = loc.y; 209 210 211 GL11.glPushMatrix(); 212 GL11.glTranslatef(x, y, 0); 213 214 GL11.glEnable(GL11.GL_TEXTURE_2D); 215 //GL11.glDisable(GL11.GL_TEXTURE_2D); 216 217 texture.bindTexture(); 218 219 GL11.glEnable(GL11.GL_BLEND); 220 221// if (layer == campaignenginelayers.terrain_10) { 222// gl11.glblendfunc(gl11.gl_src_alpha, gl11.gl_one); 223// } else { 224// gl11.glblendfunc(gl11.gl_src_alpha, gl11.gl_one_minus_src_alpha); 225// } 226 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); 227 228 float thickness = (radEnd - radStart) * 1f; 229 float radius = radStart; 230 231 float texProgress = 0f; 232 //texProgress = (float) (phaseAngle / 360f) * 10f; 233 234 235 float texHeight = texture.getTextureHeight(); 236 float imageHeight = texture.getHeight(); 237 //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight * bandWidthInTexture / thickness * 1f; 238 //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight * thickness / bandWidthInTexture; 239 //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight * params.startThickness / bandWidthInTexture; 240 float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight * bandWidthInTexture / params.startThickness; 241 texPerSegment *= 200f/256f; 242 texPerSegment *= 200f/256f; 243 //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight; 244 //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight; 245 //texPerSegment = getPixelsPerSegment() * texHeight / imageHeight; 246 //System.out.println("TPS: " + texPerSegment); 247 248 texPerSegment *= 1f; 249 250 float totalTex = Math.max(1f, Math.round(texPerSegment * segments)); 251 texPerSegment = totalTex / segments; 252 253 float texWidth = texture.getTextureWidth(); 254 float imageWidth = texture.getWidth(); 255 256// GL11.glDisable(GL11.GL_TEXTURE_2D); 257// GL11.glDisable(GL11.GL_BLEND); 258// GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE); 259// GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); 260 float fadeDist = getFadeDist(); 261 262 //float periodMult = ((float) Math.PI * 2f) / (spanRad * 4f); 263 //float periodMult = 360f / Misc.getAngleDiff(angle1, angle2) * 0.5f; 264 float periodMult = 3.1415f * 2f / spanRad * 0.25f * currentWidth / 800f; 265 //float periodMult = 3.1415f * 2f / spanRad * 0.25f * (float) Math.pow(currentWidth / 800f, .75f); 266 //float periodMult = 3.1415f * 2f / (float) Math.pow(spanRad, 0.15f) * 0.25f * currentWidth / 800f; 267 //System.out.println(periodMult); 268 //periodMult = 2f; 269 texProgress = (float) (phaseAngle / 360f) * 5f * 0.25f; 270 if (layer == CampaignEngineLayers.TERRAIN_10) { 271 periodMult *= 1.25f; 272 texProgress = (float) (phaseAngle / 360f) * -1f * 0.25f; 273 } 274 275 //float periodMult = 3.1415f * 2f / (3.1415f * 0.05f) * 0.25f; 276 //periodMult = 15f; 277 //System.out.println("P: " + periodMult); 278 //alphaMult *= 0.75f; 279 //periodMult = 20f; 280 for (int iter = 0; iter < 4; iter++) { 281 if (iter == 0) { 282 bandIndex = 1; 283 } else { 284 if (iter == 2) bandIndex = 2; 285 else if (iter == 3) bandIndex = 3; 286 else bandIndex = 0; 287 } 288 289 float leftTX = (float) bandIndex * texWidth * bandWidthInTexture / imageWidth; 290 float rightTX = (float) (bandIndex + 1f) * texWidth * bandWidthInTexture / imageWidth - 0.001f; 291 292 float temp = leftTX; 293 leftTX = rightTX; 294 rightTX = temp; 295 296 GL11.glBegin(GL11.GL_QUAD_STRIP); 297 for (float i = 0; i < segments; i++) { 298 299 //float phaseAngleRad = (float) Math.toRadians(phaseAngle + segIndex * 10) + (segIndex * anglePerSegment * 10f); 300 float phaseAngleRad; 301 float angleIncrementBase = anglePerSegment; 302 //angleIncrementBase = currentWidth / segments * 0.00075f; 303 if (iter == 0) { 304 phaseAngleRad = (float) Math.toRadians(phaseAngle) + (i * angleIncrementBase * 10f); 305 } else { //if (iter == 1) { 306 if (iter == 2) { 307 phaseAngleRad = (float) Math.toRadians(-phaseAngle) + (i * angleIncrementBase * 15f); 308 } else if (iter == 3) { 309 phaseAngleRad = (float) Math.toRadians(phaseAngle) + (i * angleIncrementBase * 5f); 310 } else { 311 phaseAngleRad = (float) Math.toRadians(-phaseAngle) + (i * angleIncrementBase * 5f); 312 } 313 //phaseAngleRad += (float) Math.PI; 314 } 315 316 317// float angle = (float) Math.toDegrees(i * anglePerSegment); 318// if (iter == 1) angle += 180; 319 320 float pulseSin = (float) Math.sin(phaseAngleRad * periodMult * 1f); 321 float pulseAmount = pulseSin * thickness * 0.25f; 322 float pulseInner = pulseAmount * 0.5f; 323 pulseInner *= 1f; 324 325// pulseInner = 0f; 326// pulseAmount = 0f; 327 //pulseInner *= Math.max(0, pulseSin - 0.5f); 328 //pulseInner *= 0f; 329 330 float r = radius; 331 332 float thicknessMult = 1.25f; 333 float thicknessFlat = 0f; 334 335 float theta = startRad + turnDir * anglePerSegment * i; 336 337 float cos = (float) Math.cos(theta); 338 float sin = (float) Math.sin(theta); 339 float x1 = cos * (r - pulseInner); 340 float y1 = sin * (r - pulseInner); 341 float x2 = cos * (r + thickness * thicknessMult - pulseAmount + thicknessFlat); 342 float y2 = sin * (r + thickness * thicknessMult - pulseAmount + thicknessFlat); 343 344 if (iter == 3) { 345 x1 = cos * (r - pulseInner - thickness * 1f); 346 y1 = sin * (r - pulseInner - thickness * 1f); 347 x2 = cos * (r + thickness * thicknessMult - pulseAmount + thicknessFlat - thickness * 0.0f); 348 y2 = sin * (r + thickness * thicknessMult - pulseAmount + thicknessFlat - thickness * 0.0f); 349 } 350 351 x1 += xOff; 352 x2 += xOff; 353 y1 += yOff; 354 y2 += yOff; 355 356// x2 += (float) (Math.cos(phaseAngleRad) * getPixelsPerSegment() * 0.33f); 357// y2 += (float) (Math.sin(phaseAngleRad) * getPixelsPerSegment() * 0.33f); 358 359 //Color color = Color.white; 360 //Color color = new Color(255,160,75); 361 Color color = Color.white; 362 float alpha = alphaMult; 363 364 float distFromEdge; 365 if (i < segments / 2f) { 366 distFromEdge = i * currentWidth / segments; 367 } else { 368 distFromEdge = (segments - i - 1f) * currentWidth / segments; 369 } 370 alpha *= Math.min(1f, distFromEdge / fadeDist); 371 372 GL11.glColor4ub((byte)color.getRed(), 373 (byte)color.getGreen(), 374 (byte)color.getBlue(), 375 (byte)((float) color.getAlpha() * alpha)); 376 377 GL11.glTexCoord2f(leftTX, texProgress); 378 GL11.glVertex2f(x1, y1); 379 GL11.glTexCoord2f(rightTX, texProgress); 380 GL11.glVertex2f(x2, y2); 381 382 texProgress += texPerSegment; 383 } 384 GL11.glEnd(); 385 //GL11.glRotatef(180, 0, 0, 1); 386 } 387 GL11.glPopMatrix(); 388 389 } 390 391 @Override 392 public float getRenderRange() { 393 return (currentThickness + currentWidth) * 0.5f + 200f; 394 } 395 396 protected void updateArcOfCurrWidth() { 397 Vector2f perp = Misc.getPerp(velDir); 398 399 p1.set(perp); 400 p2.set(perp).negate(); 401 402 p1.scale(currentWidth * 0.5f); 403 p2.scale(currentWidth * 0.5f); 404 405 Vector2f.add(p1, entity.getLocation(), p1); 406 Vector2f.add(p2, entity.getLocation(), p2); 407 408 float angle1 = Misc.getAngleInDegrees(arcOrigin, p1); 409 float angle2 = Misc.getAngleInDegrees(arcOrigin, p2); 410 411 float diff = Misc.getAngleDiff(angle1, angle2); 412 currentArc = diff; 413 } 414 415 protected float getFadeDist() { 416 float fadeDist = Math.max(300, currentWidth / numSegments * 4f); 417 if (fadeDist > currentWidth / 3f) fadeDist = currentWidth / 3f; 418 return fadeDist; 419 } 420 421 @Override 422 public boolean containsPoint(Vector2f point, float radius) { 423 if (!Misc.isInArc(params.angle, currentArc, arcOrigin, point)) { 424 return false; 425 } 426 427 float dist = Misc.getDistance(point, arcOrigin); 428 429 float max = params.arcOriginRange + distanceTravelled; 430 float min = max - currentThickness; 431 432 return dist >= min - radius && dist <= max + radius; 433 } 434 435 @Override 436 public void applyEffect(SectorEntityToken entity, float days) { 437 if (entity instanceof CampaignFleetAPI) { 438 CampaignFleetAPI fleet = (CampaignFleetAPI) entity; 439 440 float intensity = getIntensityAtPoint(fleet.getLocation()); 441 if (intensity <= 0) return; 442 443 // "wind" effect - adjust velocity 444 445 fleet.getStats().removeTemporaryMod(getModId()); 446 447 float maxFleetBurn = fleet.getFleetData().getBurnLevel(); 448 float currFleetBurn = fleet.getCurrBurnLevel(); 449 450 float maxWindBurn = params.burnLevel; 451 452 float currWindBurn = intensity * maxWindBurn; 453 float burnDiff = maxFleetBurn - currWindBurn; 454 float maxFleetBurnIntoWind = 0; 455 if (burnDiff >= 5.9f) { 456 maxFleetBurnIntoWind = -params.burnLevel + 4f; 457 } else if (burnDiff >= 3.9f) { 458 maxFleetBurnIntoWind = -params.burnLevel + 3f; 459 } else if (burnDiff >= 2.9f) { 460 maxFleetBurnIntoWind = -params.burnLevel + 2f; 461 } else if (burnDiff >= 0.9f) { 462 maxFleetBurnIntoWind = -params.burnLevel + 1f; 463 } else { 464 maxFleetBurnIntoWind = -params.burnLevel + 1f; 465 } 466 467 float angle = getForceDirAtPoint(fleet.getLocation()); 468 469 Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(angle); 470 Vector2f velDir = Misc.normalise(new Vector2f(fleet.getVelocity())); 471 float dot = Vector2f.dot(windDir, velDir); 472 473 velDir.scale(currFleetBurn); 474 float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir); 475 476 float burnBonus = (currWindBurn - maxFleetBurn) * dot; 477 if (dot > 0) { 478 burnBonus = Math.round(burnBonus); 479 if (burnBonus < 1) burnBonus = 1; 480 fleet.getStats().addTemporaryModFlat(0.1f, getModId(), "In wavefront", burnBonus, fleet.getStats().getFleetwideMaxBurnMod()); 481 } 482 483 float accelMult = 0.5f; 484 if (fleetBurnAgainstWind < maxFleetBurnIntoWind) { 485 //accelMult = 0.5f + 0.25f * Math.abs(fleetBurnAgainstWind - maxFleetBurnIntoWind); 486 accelMult = 0.5f; 487 //accelMult = 0f; 488 } else { 489 float diff = Math.abs(fleetBurnAgainstWind - maxFleetBurnIntoWind); 490 accelMult = 2f + diff * 0.25f; 491 } 492 493 float maxSpeed = fleet.getTravelSpeed(); 494 float baseAccel = Math.max(10f, maxSpeed * fleet.getStats().getAccelerationMult().getBaseValue()); 495 496 float seconds = days * Global.getSector().getClock().getSecondsPerDay(); 497 498 Vector2f vel = fleet.getVelocity(); 499 windDir.scale(seconds * baseAccel * accelMult); 500 fleet.setVelocity(vel.x + windDir.x, vel.y + windDir.y); 501 502 Color glowColor = new Color(100,200,255,75); 503 int alpha = glowColor.getAlpha(); 504 if (alpha < 75) { 505 glowColor = Misc.setAlpha(glowColor, 75); 506 } 507 508 // visual effects - glow, tail 509 float durIn = 1f; 510 float durOut = 2f; 511 Misc.normalise(windDir); 512 float sizeNormal = 5f + 10f * intensity; 513 for (FleetMemberViewAPI view : fleet.getViews()) { 514 view.getWindEffectDirX().shift(getModId(), windDir.x * sizeNormal, durIn, durOut, 1f); 515 view.getWindEffectDirY().shift(getModId(), windDir.y * sizeNormal, durIn, durOut, 1f); 516 //view.getWindEffectColor().shift(getModId(), glowColor, durIn, durOut, intensity); 517 view.getWindEffectColor().shift(getModId(), glowColor, durIn, durOut, intensity); 518 } 519 } 520 521 } 522 523 524 525 public float getForceDirAtPoint(Vector2f point) { 526 float angle1 = Misc.getAngleInDegrees(arcOrigin, p1); 527 float angle2 = Misc.getAngleInDegrees(arcOrigin, p2); 528 529 float angle3 = Misc.getAngleInDegrees(arcOrigin, point); 530 531 float widthPerDegree = currentWidth / Misc.getAngleDiff(angle1, angle2); 532 533 float dist1 = Misc.getAngleDiff(angle1, angle3) * widthPerDegree; 534 float dist2 = Misc.getAngleDiff(angle2, angle3) * widthPerDegree; 535 536 float fadeDist = getFadeDist(); 537 538 float turnDir = 0f; 539 float brightness = 0f; 540 if (dist1 < fadeDist && dist1 <= dist2) { 541 brightness = dist1 / fadeDist; 542 turnDir = Misc.getClosestTurnDirection(angle3, arcOrigin, p1); 543 } 544 545 if (dist2 < fadeDist && dist2 <= dist1) { 546 brightness = dist2 / fadeDist; 547 turnDir = Misc.getClosestTurnDirection(angle3, arcOrigin, p2); 548 } 549 550 return angle3 + (1f - brightness) * 45f * turnDir; 551 } 552 553 public float getIntensityAtPoint(Vector2f point) { 554 float angle1 = Misc.getAngleInDegrees(arcOrigin, p1); 555 float angle2 = Misc.getAngleInDegrees(arcOrigin, p2); 556 557 float angle3 = Misc.getAngleInDegrees(arcOrigin, point); 558 559 if (!Misc.isBetween(angle1, angle2, angle3)) return 0f; 560 561 float widthPerDegree = currentWidth / Misc.getAngleDiff(angle1, angle2); 562 563 float dist1 = Misc.getAngleDiff(angle1, angle3) * widthPerDegree; 564 float dist2 = Misc.getAngleDiff(angle2, angle3) * widthPerDegree; 565 566 float fadeDist = getFadeDist(); 567 568 float sideMult = 1f; 569 if (dist1 < fadeDist && dist1 <= dist2) { 570 sideMult = dist1 / fadeDist; 571 } 572 if (dist2 < fadeDist && dist2 <= dist1) { 573 sideMult = dist2 / fadeDist; 574 } 575 576 float distToPoint = Misc.getDistance(arcOrigin, point); 577 float max = params.arcOriginRange + distanceTravelled; 578 float min = max - currentThickness; 579 580 max = max - min; 581 distToPoint -= min; 582 min = 0; 583 float f = distToPoint / max; 584 585 if (f > 0.75f) { 586 f = (1f - f) / .25f; 587 } else if (f < 0.25f) { 588 f = f / 0.25f; 589 } else { 590 f = 1f; 591 } 592 593 return sideMult * f * fader.getBrightness(); 594 } 595 596 @Override 597 public Color getNameColor() { 598 Color bad = Misc.getNegativeHighlightColor(); 599 Color base = super.getNameColor(); 600 return Misc.interpolateColor(base, bad, Global.getSector().getCampaignUI().getSharedFader().getBrightness() * 1f); 601 } 602 603 public boolean hasTooltip() { 604 return true; 605 } 606 607 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) { 608 float pad = 10f; 609 float small = 5f; 610 Color gray = Misc.getGrayColor(); 611 Color highlight = Misc.getHighlightColor(); 612 Color fuel = Global.getSettings().getColor("progressBarFuelColor"); 613 Color bad = Misc.getNegativeHighlightColor(); 614 615 tooltip.addTitle("Wavefront"); 616 tooltip.addPara(Global.getSettings().getDescription(getTerrainId(), Type.TERRAIN).getText1(), pad); 617 618 float nextPad = pad; 619 if (expanded) { 620 tooltip.addSectionHeading("Travel", Alignment.MID, pad); 621 nextPad = small; 622 } 623 tooltip.addPara("Reduces the combat readiness of " + 624 "all ships in the corona at a steady pace.", nextPad); 625 tooltip.addPara("The heavy solar wind also makes the star difficult to approach.", pad); 626 tooltip.addPara("Occasional solar flare activity takes these effects to even more dangerous levels.", pad); 627 628 if (expanded) { 629 tooltip.addSectionHeading("Combat", Alignment.MID, pad); 630 tooltip.addPara("Reduces the peak performance time of ships and increases the rate of combat readiness degradation in protracted engagements.", small); 631 } 632 633 //tooltip.addPara("Does not stack with other similar terrain effects.", pad); 634 } 635 636 public boolean isTooltipExpandable() { 637 return true; 638 } 639 640 public float getTooltipWidth() { 641 return 350f; 642 } 643 644 public String getTerrainName() { 645 return "Wavefront"; 646 } 647 648 public String getNameForTooltip() { 649 return getTerrainName(); 650 } 651 652 public String getEffectCategory() { 653 return null; 654 } 655 656 657 public float getMaxEffectRadius(Vector2f locFrom) { 658 return getRenderRange(); 659 } 660 public float getMinEffectRadius(Vector2f locFrom) { 661 return 0f; 662 } 663 664 public float getOptimalEffectRadius(Vector2f locFrom) { 665 return getMaxEffectRadius(locFrom); 666 } 667 668 public boolean hasMapIcon() { 669 return false; 670 } 671 672 public boolean canPlayerHoldStationIn() { 673 return false; 674 } 675} 676 677 678 679 680